chore: refactor for sonarqube issues
SonarQube Analysis / sonarqube (pull_request) Successful in 6m3s
SonarQube Analysis / sonarqube (pull_request) Successful in 6m3s
This commit is contained in:
@@ -124,101 +124,7 @@ public class ProcedureBreakdown : SqlServerProcedureBreakdown
|
||||
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sql))
|
||||
{
|
||||
errorMessage = "SQL statement cannot be null or empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// If Microsoft SQL mode, delegate to base class
|
||||
if (isMicrosoftSql)
|
||||
{
|
||||
if (!SqlServerProcedureBreakdown.TryParse(sql, out var baseResult, out errorMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to Snowflake ProcedureBreakdown
|
||||
result = new ProcedureBreakdown
|
||||
{
|
||||
ProcedureName = baseResult.ProcedureName,
|
||||
Parameters = baseResult.Parameters,
|
||||
SetupClauses = baseResult.SetupClauses,
|
||||
FinishClauses = baseResult.FinishClauses
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var parser = SnowflakeParserInstance;
|
||||
sql = parser.NormalizeSqlPreservingComments(sql);
|
||||
|
||||
// Check if it's a CALL statement (Snowflake syntax) or EXEC (for compatibility)
|
||||
var sqlTrimmed = sql.TrimStart();
|
||||
if (!System.Text.RegularExpressions.Regex.IsMatch(sqlTrimmed, @"^\s*(CALL|EXEC|EXECUTE)\b",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase, Strata.SqlTools.SqlBreakdown.Utilities.RegexDefaults.MatchTimeout))
|
||||
{
|
||||
errorMessage = "SQL statement must start with CALL, EXEC, or EXECUTE.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract setup and finish clauses
|
||||
var setupClauses = new List<string>();
|
||||
sql = parser.ExtractSetupClauses(sql, setupClauses);
|
||||
|
||||
var finishClauses = new ArrayList();
|
||||
sql = parser.ExtractFinishClauses(sql, finishClauses);
|
||||
|
||||
// Parse CALL statement - match procedure name and parameters
|
||||
// Pattern: CALL procedureName(param => value, ...)
|
||||
var callMatch = System.Text.RegularExpressions.Regex.Match(sql,
|
||||
@"(?:CALL|EXEC|EXECUTE)\s+([^\s\(]+)(?:\s*\((.*?)\))?$",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline, Strata.SqlTools.SqlBreakdown.Utilities.RegexDefaults.MatchTimeout);
|
||||
|
||||
if (!callMatch.Success)
|
||||
{
|
||||
errorMessage = "Could not parse CALL statement. Expected format: CALL procedureName(param => value, ...)";
|
||||
return false;
|
||||
}
|
||||
|
||||
var procedureName = callMatch.Groups[1].Value.Trim();
|
||||
var parametersText = callMatch.Groups.Count > 2 ? callMatch.Groups[2].Value.Trim() : string.Empty;
|
||||
|
||||
var parameters = new Dictionary<string, string>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(parametersText))
|
||||
{
|
||||
// Parse parameters - Snowflake uses param => value syntax
|
||||
var paramMatches = System.Text.RegularExpressions.Regex.Matches(parametersText,
|
||||
@"(\w+)\s*=>\s*([^,]+)(?:,|$)",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase, Strata.SqlTools.SqlBreakdown.Utilities.RegexDefaults.MatchTimeout);
|
||||
|
||||
foreach (System.Text.RegularExpressions.Match paramMatch in paramMatches)
|
||||
{
|
||||
var paramName = paramMatch.Groups[1].Value.Trim();
|
||||
var paramValue = paramMatch.Groups[2].Value.Trim();
|
||||
// Store with @ prefix for consistency with SQL Server
|
||||
parameters["@" + paramName] = paramValue;
|
||||
}
|
||||
|
||||
// If no named parameters found, try positional parameters (just values)
|
||||
if (parameters.Count == 0 && !string.IsNullOrWhiteSpace(parametersText))
|
||||
{
|
||||
var positionalParams = parametersText.Split(',');
|
||||
for (int i = 0; i < positionalParams.Length; i++)
|
||||
{
|
||||
parameters[$"@param{i + 1}"] = positionalParams[i].Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = new ProcedureBreakdown(procedureName, parameters, isMicrosoftSql: false)
|
||||
{
|
||||
SetupClauses = setupClauses,
|
||||
FinishClauses = finishClauses
|
||||
};
|
||||
|
||||
return true;
|
||||
return TryParseCore(sql, out result, out errorMessage, isMicrosoftSql);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -227,5 +133,128 @@ public class ProcedureBreakdown : SqlServerProcedureBreakdown
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryParseCore(string sql, out ProcedureBreakdown result, out string errorMessage, bool isMicrosoftSql)
|
||||
{
|
||||
result = null!;
|
||||
errorMessage = null!;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(sql))
|
||||
{
|
||||
errorMessage = "SQL statement cannot be null or empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// If Microsoft SQL mode, delegate to base class
|
||||
if (isMicrosoftSql)
|
||||
{
|
||||
return TryParseMicrosoftSql(sql, out result, out errorMessage);
|
||||
}
|
||||
|
||||
var parser = SnowflakeParserInstance;
|
||||
sql = parser.NormalizeSqlPreservingComments(sql);
|
||||
|
||||
// Check if it's a CALL statement (Snowflake syntax) or EXEC (for compatibility)
|
||||
var sqlTrimmed = sql.TrimStart();
|
||||
if (!System.Text.RegularExpressions.Regex.IsMatch(sqlTrimmed, @"^\s*(CALL|EXEC|EXECUTE)\b",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase, Strata.SqlTools.SqlBreakdown.Utilities.RegexDefaults.MatchTimeout))
|
||||
{
|
||||
errorMessage = "SQL statement must start with CALL, EXEC, or EXECUTE.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract setup and finish clauses
|
||||
var setupClauses = new List<string>();
|
||||
sql = parser.ExtractSetupClauses(sql, setupClauses);
|
||||
|
||||
var finishClauses = new ArrayList();
|
||||
sql = parser.ExtractFinishClauses(sql, finishClauses);
|
||||
|
||||
// Parse CALL statement - match procedure name and parameters
|
||||
// Pattern: CALL procedureName(param => value, ...)
|
||||
var callMatch = System.Text.RegularExpressions.Regex.Match(sql,
|
||||
@"(?:CALL|EXEC|EXECUTE)\s+([^\s\(]+)(?:\s*\((.*?)\))?$",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline, Strata.SqlTools.SqlBreakdown.Utilities.RegexDefaults.MatchTimeout);
|
||||
|
||||
if (!callMatch.Success)
|
||||
{
|
||||
errorMessage = "Could not parse CALL statement. Expected format: CALL procedureName(param => value, ...)";
|
||||
return false;
|
||||
}
|
||||
|
||||
var procedureName = callMatch.Groups[1].Value.Trim();
|
||||
var parametersText = callMatch.Groups.Count > 2 ? callMatch.Groups[2].Value.Trim() : string.Empty;
|
||||
|
||||
result = new ProcedureBreakdown(procedureName, ParseCallParameters(parametersText), isMicrosoftSql: false)
|
||||
{
|
||||
SetupClauses = setupClauses,
|
||||
FinishClauses = finishClauses
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses Microsoft T-SQL CALL/EXEC syntax by delegating to the SQL Server breakdown,
|
||||
/// then projecting the result onto a Snowflake <see cref="ProcedureBreakdown"/>.
|
||||
/// </summary>
|
||||
private static bool TryParseMicrosoftSql(string sql, out ProcedureBreakdown result, out string errorMessage)
|
||||
{
|
||||
result = null!;
|
||||
|
||||
if (!SqlServerProcedureBreakdown.TryParse(sql, out var baseResult, out errorMessage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new ProcedureBreakdown
|
||||
{
|
||||
ProcedureName = baseResult.ProcedureName,
|
||||
Parameters = baseResult.Parameters,
|
||||
SetupClauses = baseResult.SetupClauses,
|
||||
FinishClauses = baseResult.FinishClauses
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the parameter list of a Snowflake CALL statement. Supports named (<c>param => value</c>)
|
||||
/// syntax, falling back to positional values when no named parameters are present.
|
||||
/// </summary>
|
||||
private static Dictionary<string, string> ParseCallParameters(string parametersText)
|
||||
{
|
||||
var parameters = new Dictionary<string, string>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(parametersText))
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
|
||||
// Parse parameters - Snowflake uses param => value syntax
|
||||
var paramMatches = System.Text.RegularExpressions.Regex.Matches(parametersText,
|
||||
@"(\w+)\s*=>\s*([^,]+)(?:,|$)",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase, Strata.SqlTools.SqlBreakdown.Utilities.RegexDefaults.MatchTimeout);
|
||||
|
||||
foreach (System.Text.RegularExpressions.Match paramMatch in paramMatches)
|
||||
{
|
||||
var paramName = paramMatch.Groups[1].Value.Trim();
|
||||
var paramValue = paramMatch.Groups[2].Value.Trim();
|
||||
// Store with @ prefix for consistency with SQL Server
|
||||
parameters["@" + paramName] = paramValue;
|
||||
}
|
||||
|
||||
// If no named parameters found, try positional parameters (just values)
|
||||
if (parameters.Count == 0)
|
||||
{
|
||||
var positionalParams = parametersText.Split(',');
|
||||
for (int i = 0; i < positionalParams.Length; i++)
|
||||
{
|
||||
parameters[$"@param{i + 1}"] = positionalParams[i].Trim();
|
||||
}
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user