125 lines
3.9 KiB
C#
125 lines
3.9 KiB
C#
using System.Text;
|
|
|
|
namespace Strata.SqlTools.SqlServer.Exceptions;
|
|
|
|
/// <summary>
|
|
/// Exception thrown when SQL parsing fails.
|
|
/// Provides detailed context about the parse failure including position and surrounding text.
|
|
/// </summary>
|
|
public class SqlParseException : Exception
|
|
{
|
|
/// <summary>
|
|
/// Gets the position in the SQL string where the parse error occurred.
|
|
/// </summary>
|
|
public int Position { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the SQL statement that failed to parse.
|
|
/// </summary>
|
|
public string Sql { get; }
|
|
|
|
/// <summary>
|
|
/// Gets the text near the error position (up to 40 characters).
|
|
/// </summary>
|
|
public string NearText { get; }
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="SqlParseException"/> class.
|
|
/// </summary>
|
|
/// <param name="message">The error message describing the parse failure.</param>
|
|
/// <param name="sql">The SQL statement that failed to parse.</param>
|
|
/// <param name="position">The position in the SQL where the error occurred.</param>
|
|
/// <example>
|
|
/// <code>
|
|
/// throw new SqlParseException(
|
|
/// "Unexpected token 'FROM'",
|
|
/// "SELECT * FRM users",
|
|
/// 10
|
|
/// );
|
|
/// // Message will include:
|
|
/// // - Error description
|
|
/// // - Position: 10
|
|
/// // - Near: "* FRM users"
|
|
/// // - Full SQL statement
|
|
/// </code>
|
|
/// </example>
|
|
public SqlParseException(string message, string sql, int position)
|
|
: base(FormatMessage(message, sql, position))
|
|
{
|
|
Position = position;
|
|
Sql = sql ?? string.Empty;
|
|
NearText = ExtractNearText(Sql, position);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="SqlParseException"/> class with an inner exception.
|
|
/// </summary>
|
|
/// <param name="message">The error message describing the parse failure.</param>
|
|
/// <param name="sql">The SQL statement that failed to parse.</param>
|
|
/// <param name="position">The position in the SQL where the error occurred.</param>
|
|
/// <param name="innerException">The exception that caused this parse failure.</param>
|
|
public SqlParseException(string message, string sql, int position, Exception innerException)
|
|
: base(FormatMessage(message, sql, position), innerException)
|
|
{
|
|
Position = position;
|
|
Sql = sql ?? string.Empty;
|
|
NearText = ExtractNearText(Sql, position);
|
|
}
|
|
|
|
private static string FormatMessage(string message, string sql, int position)
|
|
{
|
|
if (string.IsNullOrEmpty(sql))
|
|
{
|
|
return $"{message}\nSQL statement is empty or null.";
|
|
}
|
|
|
|
var nearText = ExtractNearText(sql, position);
|
|
var sb = new StringBuilder();
|
|
|
|
sb.AppendLine(message);
|
|
sb.AppendLine($"Position: {position}");
|
|
sb.AppendLine($"Near: '{nearText}'");
|
|
|
|
// Show full SQL for short statements, truncated for long ones
|
|
if (sql.Length <= 200)
|
|
{
|
|
sb.AppendLine($"Full SQL: {sql}");
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine($"SQL (truncated): {sql.Substring(0, 197)}...");
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
private static string ExtractNearText(string sql, int position)
|
|
{
|
|
if (string.IsNullOrEmpty(sql))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
// Clamp position to valid range
|
|
position = Math.Max(0, Math.Min(position, sql.Length));
|
|
|
|
// Extract up to 20 chars before and 20 chars after the position
|
|
var start = Math.Max(0, position - 20);
|
|
var length = Math.Min(40, sql.Length - start);
|
|
|
|
var nearText = sql.Substring(start, length);
|
|
|
|
// Add ellipsis if truncated
|
|
if (start > 0)
|
|
{
|
|
nearText = "..." + nearText;
|
|
}
|
|
if (start + length < sql.Length)
|
|
{
|
|
nearText = nearText + "...";
|
|
}
|
|
|
|
return nearText;
|
|
}
|
|
}
|