feat(etl): add ParseTableName and QUOTENAME to CommonScripts

- Add ParseTableName method to parse table names with optional schema
  - Supports: "Table", "dbo.Table", "[dbo].[Table]"
  - Returns (schema, table) tuple, defaults to "dbo" schema
- Update DisableIndexes, RebuildIndexes, UpdateStatistics to:
  - Use QUOTENAME() for SQL injection protection
  - Pass schema and table as parameters via SqlScriptRunner
  - Support non-dbo schemas
- Update CustomSql to accept optional parameters and timeout
- Add comprehensive tests for ParseTableName with various formats
This commit is contained in:
Joseph Doherty
2026-01-03 10:56:05 -05:00
parent 40e458148d
commit 0e07a76438
2 changed files with 129 additions and 16 deletions
@@ -5,35 +5,85 @@ namespace JdeScoping.DataSync.Etl.Scripts;
public static class CommonScripts
{
public static IScriptRunner DisableIndexes(IDbConnectionFactory factory, string tableName)
/// <summary>
/// Parses a table name, extracting schema if present.
/// Supports: "Table", "dbo.Table", "[dbo].[Table]"
/// </summary>
public static (string Schema, string Table) ParseTableName(string tableName)
{
var sql = $@"
var cleaned = tableName.Replace("[", "").Replace("]", "");
var parts = cleaned.Split('.', 2);
return parts.Length == 2
? (parts[0], parts[1])
: ("dbo", parts[0]);
}
public static IScriptRunner DisableIndexes(
IDbConnectionFactory factory,
string tableName,
int timeoutSeconds = 300)
{
var (schema, table) = ParseTableName(tableName);
var sql = @"
DECLARE @sql NVARCHAR(MAX) = '';
SELECT @sql = @sql + 'ALTER INDEX [' + i.name + '] ON [{tableName}] DISABLE;' + CHAR(13)
DECLARE @fullTableName NVARCHAR(256) = QUOTENAME(@schemaName) + '.' + QUOTENAME(@tableName);
SELECT @sql = @sql + 'ALTER INDEX ' + QUOTENAME(i.name) + ' ON ' + @fullTableName + ' DISABLE;' + CHAR(13)
FROM sys.indexes i
INNER JOIN sys.tables t ON i.object_id = t.object_id
WHERE t.name = '{tableName}'
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE t.name = @tableName
AND s.name = @schemaName
AND i.type = 2
AND i.is_disabled = 0;
IF LEN(@sql) > 0 EXEC sp_executesql @sql;";
return new SqlScriptRunner(factory, sql, $"DisableIndexes:{tableName}", timeoutSeconds: 300);
return new SqlScriptRunner(factory, sql, $"DisableIndexes:{schema}.{table}",
parameters: new { tableName = table, schemaName = schema },
timeoutSeconds: timeoutSeconds);
}
public static IScriptRunner RebuildIndexes(IDbConnectionFactory factory, string tableName)
public static IScriptRunner RebuildIndexes(
IDbConnectionFactory factory,
string tableName,
int timeoutSeconds = 3600)
{
var sql = $"ALTER INDEX ALL ON [{tableName}] REBUILD WITH (FILLFACTOR = 95)";
return new SqlScriptRunner(factory, sql, $"RebuildIndexes:{tableName}", timeoutSeconds: 3600);
var (schema, table) = ParseTableName(tableName);
var sql = @"
DECLARE @sql NVARCHAR(256) = 'ALTER INDEX ALL ON ' + QUOTENAME(@schemaName) + '.' + QUOTENAME(@tableName) + ' REBUILD WITH (FILLFACTOR = 95)';
EXEC sp_executesql @sql;";
return new SqlScriptRunner(factory, sql, $"RebuildIndexes:{schema}.{table}",
parameters: new { tableName = table, schemaName = schema },
timeoutSeconds: timeoutSeconds);
}
public static IScriptRunner UpdateStatistics(IDbConnectionFactory factory, string tableName)
public static IScriptRunner UpdateStatistics(
IDbConnectionFactory factory,
string tableName,
int timeoutSeconds = 600)
{
var sql = $"UPDATE STATISTICS [{tableName}]";
return new SqlScriptRunner(factory, sql, $"UpdateStats:{tableName}", timeoutSeconds: 600);
var (schema, table) = ParseTableName(tableName);
var sql = @"
DECLARE @sql NVARCHAR(256) = 'UPDATE STATISTICS ' + QUOTENAME(@schemaName) + '.' + QUOTENAME(@tableName);
EXEC sp_executesql @sql;";
return new SqlScriptRunner(factory, sql, $"UpdateStats:{schema}.{table}",
parameters: new { tableName = table, schemaName = schema },
timeoutSeconds: timeoutSeconds);
}
public static IScriptRunner CustomSql(IDbConnectionFactory factory, string sql, string name)
public static IScriptRunner CustomSql(
IDbConnectionFactory factory,
string sql,
string name,
object? parameters = null,
int timeoutSeconds = 30)
{
return new SqlScriptRunner(factory, sql, name);
return new SqlScriptRunner(factory, sql, name, parameters, timeoutSeconds);
}
}