Documentation
¶
Overview ¶
Package errors provides a structured error system for GoSQLX v1.6.0 with rich context, intelligent suggestions, and comprehensive error codes.
This package delivers production-grade error handling for SQL parsing with:
- Structured Error Codes: E1xxx-E4xxx for programmatic error handling
- Precise Location Tracking: Line and column information for every error
- SQL Context Extraction: Visual error highlighting in source code
- Intelligent Hints: Auto-generated suggestions using Levenshtein distance
- Typo Detection: "Did you mean?" suggestions for common mistakes
- Error Recovery: Graceful degradation with actionable feedback
Error Code Taxonomy ¶
Errors are categorized into four main groups:
E1xxx - Tokenizer Errors:
- E1001: ErrCodeUnexpectedChar - Invalid character in SQL input
- E1002: ErrCodeUnterminatedString - Missing closing quote
- E1003: ErrCodeInvalidNumber - Malformed numeric literal
- E1004: ErrCodeInvalidOperator - Invalid operator sequence
- E1005: ErrCodeInvalidIdentifier - Malformed identifier
- E1006: ErrCodeInputTooLarge - Input exceeds size limits (DoS protection)
- E1007: ErrCodeTokenLimitReached - Token count exceeds limit (DoS protection)
- E1008: ErrCodeTokenizerPanic - Recovered panic (bug detection)
E2xxx - Parser Syntax Errors:
- E2001: ErrCodeUnexpectedToken - Unexpected token in grammar
- E2002: ErrCodeExpectedToken - Missing required token
- E2003: ErrCodeMissingClause - Required SQL clause missing
- E2004: ErrCodeInvalidSyntax - General syntax violation
- E2005: ErrCodeIncompleteStatement - Incomplete SQL statement
- E2006: ErrCodeInvalidExpression - Invalid expression syntax
- E2007: ErrCodeRecursionDepthLimit - Recursion too deep (DoS protection)
- E2008: ErrCodeUnsupportedDataType - Data type not supported
- E2009: ErrCodeUnsupportedConstraint - Constraint type not supported
- E2010: ErrCodeUnsupportedJoin - JOIN type not supported
- E2011: ErrCodeInvalidCTE - Invalid CTE (WITH clause) syntax
- E2012: ErrCodeInvalidSetOperation - Invalid UNION/EXCEPT/INTERSECT
E3xxx - Semantic Errors:
- E3001: ErrCodeUndefinedTable - Table reference not found
- E3002: ErrCodeUndefinedColumn - Column reference not found
- E3003: ErrCodeTypeMismatch - Type incompatibility in expression
- E3004: ErrCodeAmbiguousColumn - Column appears in multiple tables
E4xxx - Unsupported Features:
- E4001: ErrCodeUnsupportedFeature - Feature not yet implemented
- E4002: ErrCodeUnsupportedDialect - SQL dialect not supported
Core Components ¶
Error Structure:
- Error: Main error type with code, message, location, context, hint
- ErrorCode: Strongly-typed error code (string type)
- ErrorContext: SQL source context with highlighting
Builder Functions:
- UnexpectedTokenError, ExpectedTokenError, MissingClauseError
- InvalidSyntaxError, UnsupportedFeatureError, IncompleteStatementError
- All E1xxx-E4xxx errors have dedicated builder functions
Suggestion System:
- GenerateHint: Auto-generates context-aware suggestions
- SuggestKeyword: Levenshtein-based typo correction
- SuggestFromPattern: Regex-based pattern matching
- CommonHints: Pre-built hints for frequent errors
Formatting Functions:
- FormatErrorWithContext: Full error with SQL context
- FormatErrorSummary: Brief error for logging
- FormatErrorList: Multiple errors in readable format
- FormatContextWindow: Larger context (N lines before/after)
Performance and Caching ¶
The error system is optimized for production use:
- Keyword suggestion cache (1000 entries) for fast typo detection
- Cache hit rate: 85%+ in LSP scenarios with repeated typos
- Lock-free atomic metrics for cache statistics
- Partial eviction strategy (keeps 50% on overflow)
- Thread-safe cache operations for concurrent use
Cache Management:
// Check cache statistics
stats := errors.GetSuggestionCacheStats()
fmt.Printf("Hit rate: %.2f%%\n", stats.HitRate*100)
// Clear cache if needed
errors.ClearSuggestionCache()
// Reset metrics
errors.ResetSuggestionCacheStats()
Usage Examples ¶
Basic error creation with context:
err := errors.NewError(
errors.ErrCodeUnexpectedToken,
"unexpected token: COMMA",
models.Location{Line: 5, Column: 20},
)
err = err.WithContext(sqlSource, 1)
err = err.WithHint("Expected FROM keyword after SELECT clause")
Using builder functions:
err := errors.ExpectedTokenError(
"FROM", "FORM",
models.Location{Line: 1, Column: 15},
sqlSource,
)
// Automatically includes context and "Did you mean 'FROM'?" hint
Handling errors in application code:
if err != nil {
if errors.IsCode(err, errors.ErrCodeUnterminatedString) {
// Handle unterminated string specifically
}
code := errors.GetCode(err)
switch code {
case errors.ErrCodeExpectedToken:
// Handle syntax errors
case errors.ErrCodeUndefinedTable:
// Handle semantic errors
}
// Extract location for IDE integration
if loc, ok := errors.ExtractLocation(err); ok {
fmt.Printf("Error at line %d, column %d\n", loc.Line, loc.Column)
}
}
Formatting errors for display:
// Full error with context formatted := errors.FormatErrorWithContext(err, sqlSource) fmt.Println(formatted) // Output: // Error E2002 at line 1, column 15: expected FROM, got FORM // // 1 | SELECT * FORM users WHERE id = 1 // ^^^^ // 2 | // // Hint: Did you mean 'FROM' instead of 'FORM'? // Help: https://github.com/ajitpratap0/GoSQLX/blob/main/docs/ERROR_CODES.md // Brief summary for logging summary := errors.FormatErrorSummary(err) // Output: [E2002] expected FROM, got FORM at line 1, column 15
Intelligent Suggestions ¶
The package provides sophisticated error suggestions:
Typo Detection:
// Detects common SQL keyword typos
suggestion := errors.SuggestKeyword("SELCT")
// Returns: "SELECT"
suggestion = errors.SuggestKeyword("WAHER")
// Returns: "WHERE"
Pattern-Based Suggestions:
// Matches error messages against known patterns
hint := errors.SuggestFromPattern("expected FROM but got FORM")
// Returns: "Check spelling of SQL keywords (e.g., FORM → FROM)"
Context-Aware Suggestions:
// Window function errors
hint := errors.SuggestForWindowFunction("SELECT ROW_NUMBER()", "ROW_NUMBER")
// Returns: "Window function ROW_NUMBER requires OVER clause..."
// CTE errors
hint := errors.SuggestForCTE("WITH cte AS (SELECT * FROM users)")
// Returns: "WITH clause must be followed by SELECT, INSERT, UPDATE..."
// JOIN errors
hint := errors.SuggestForJoinError("INNER", "FROM users INNER JOIN orders")
// Returns: "INNER JOIN requires ON condition or USING clause..."
Common Mistake Detection ¶
The package includes 20+ common SQL mistake patterns:
// Get mistake explanation
if mistake, ok := errors.GetMistakeExplanation("window_function_without_over"); ok {
fmt.Println(errors.FormatMistakeExample(mistake))
// Output:
// Common Mistake: window_function_without_over
// ❌ Wrong: SELECT name, ROW_NUMBER() FROM employees
// ✓ Right: SELECT name, ROW_NUMBER() OVER (ORDER BY salary DESC) FROM employees
// Explanation: Window functions require OVER clause with optional PARTITION BY and ORDER BY
}
Common mistakes include:
- window_function_without_over, partition_by_without_over
- cte_without_select, recursive_cte_without_union
- window_frame_without_order, window_function_in_where
- missing_comma_in_list, missing_join_condition
- wrong_aggregate_syntax, missing_group_by, having_without_group_by
v1.6.0 Feature Support ¶
Error handling for PostgreSQL extensions:
// LATERAL JOIN errors
err := errors.InvalidSyntaxError(
"LATERAL requires subquery or table function",
location, sqlSource,
)
// JSON operator errors
err := errors.UnexpectedTokenError("->", "ARROW", location, sqlSource)
// RETURNING clause errors
err := errors.MissingClauseError("RETURNING", location, sqlSource)
Error handling for advanced SQL features:
// Window function errors
err := errors.InvalidSyntaxError(
"window frame requires ORDER BY clause",
location, sqlSource,
)
// GROUPING SETS errors
err := errors.InvalidSyntaxError(
"GROUPING SETS requires parenthesized expression list",
location, sqlSource,
)
// MERGE statement errors
err := errors.InvalidSyntaxError(
"MERGE requires MATCHED or NOT MATCHED clause",
location, sqlSource,
)
Thread Safety and Concurrency ¶
All error operations are thread-safe:
- Error creation is safe for concurrent use
- Suggestion cache uses sync.RWMutex for concurrent reads
- Atomic operations for cache metrics
- No shared mutable state in error instances
- Safe for use in LSP server with multiple clients
IDE and LSP Integration ¶
The error system integrates seamlessly with IDE tooling:
// Extract location for diagnostic
loc, ok := errors.ExtractLocation(err)
diagnostic := lsp.Diagnostic{
Range: lsp.Range{
Start: lsp.Position{Line: loc.Line - 1, Character: loc.Column - 1},
},
Severity: lsp.DiagnosticSeverityError,
Code: string(errors.GetCode(err)),
Message: err.Error(),
}
Error Recovery and Debugging ¶
DoS Protection Errors:
// Input size limits err := errors.InputTooLargeError(10*1024*1024, 5*1024*1024, location) // Message: "input size 10485760 bytes exceeds limit of 5242880 bytes" // Hint: "Reduce input size to under 5242880 bytes or adjust MaxInputSize configuration" // Token count limits err := errors.TokenLimitReachedError(15000, 10000, location, sqlSource) // Message: "token count 15000 exceeds limit of 10000 tokens" // Hint: "Simplify query or adjust MaxTokens limit (currently 10000)"
Panic Recovery:
err := errors.TokenizerPanicError(panicValue, location) // Message: "tokenizer panic recovered: <panic value>" // Hint: "This indicates a serious tokenizer bug. Please report this issue..."
Design Principles ¶
The error package follows GoSQLX design philosophy:
- Actionable Messages: Every error includes what went wrong and how to fix it
- Precise Location: Exact line/column for every error
- Visual Context: SQL source highlighting for quick debugging
- Smart Suggestions: Levenshtein distance for typo detection
- Caching: Fast repeated suggestions for LSP scenarios
- Extensible: Easy to add new error codes and patterns
Testing and Quality ¶
The package maintains high quality standards:
- Comprehensive test coverage for all error codes
- Suggestion accuracy validation with real typos
- Cache performance benchmarks
- Thread safety validation (go test -race)
- Real-world error message validation
For complete documentation and examples, see:
- docs/GETTING_STARTED.md - Quick start guide
- docs/USAGE_GUIDE.md - Comprehensive usage documentation
- docs/LSP_GUIDE.md - IDE integration with error diagnostics
Package errors provides a structured error system for GoSQLX with error codes, context extraction, and intelligent hints for debugging SQL parsing issues.
This package is designed to provide clear, actionable error messages for SQL parsing failures. It is the production-grade error handling system for GoSQLX v1.6.0 with support for:
- Structured error codes (E1xxx-E4xxx)
- Precise location tracking with line/column information
- SQL context extraction with visual highlighting
- Intelligent suggestions using Levenshtein distance for typo detection
- Cached suggestions for performance in LSP scenarios
- Thread-safe concurrent error handling
See doc.go for comprehensive package documentation and examples.
Example (AllErrorCodes) ¶
Example_allErrorCodes demonstrates all available error codes
package main
import (
"fmt"
)
func main() {
fmt.Println("Available Error Codes:")
fmt.Println()
fmt.Println("Tokenizer Errors (E1xxx):")
fmt.Println(" E1001: Unexpected character")
fmt.Println(" E1002: Unterminated string")
fmt.Println(" E1003: Invalid number")
fmt.Println(" E1004: Invalid operator")
fmt.Println(" E1005: Invalid identifier")
fmt.Println()
fmt.Println("Parser Errors (E2xxx):")
fmt.Println(" E2001: Unexpected token")
fmt.Println(" E2002: Expected token")
fmt.Println(" E2003: Missing clause")
fmt.Println(" E2004: Invalid syntax")
fmt.Println(" E2005: Incomplete statement")
fmt.Println(" E2006: Invalid expression")
fmt.Println()
fmt.Println("Semantic Errors (E3xxx):")
fmt.Println(" E3001: Undefined table")
fmt.Println(" E3002: Undefined column")
fmt.Println(" E3003: Type mismatch")
fmt.Println(" E3004: Ambiguous column")
fmt.Println()
fmt.Println("Unsupported Features (E4xxx):")
fmt.Println(" E4001: Unsupported feature")
fmt.Println(" E4002: Unsupported dialect")
}
Example (BasicError) ¶
Example_basicError demonstrates creating a basic structured error
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FORM users"
location := models.Location{Line: 1, Column: 10}
err := errors.ExpectedTokenError("FROM", "FORM", location, sql)
fmt.Println(err.Error())
// Output includes:
// - Error code
// - Location (line and column)
// - SQL context with position indicator
// - Intelligent hint suggesting the correction
}
Example (BatchValidation) ¶
Example_batchValidation demonstrates validating multiple SQL statements
package main
import (
"fmt"
)
func main() {
statements := []string{
"SELECT * FROM users", // Valid
"SELECT * FORM users", // Typo
"SELECT * FROM", // Incomplete
"SELECT id name FROM users", // Missing comma
"INSERT users VALUES (1, 'x')", // Missing INTO
}
fmt.Println("Batch Validation Results:")
fmt.Println()
for i, stmt := range statements {
fmt.Printf("%d. %s\n", i+1, stmt)
// In real usage, parser would validate each statement
// and report errors with full context
}
fmt.Println()
fmt.Println("Validation would show:")
fmt.Println("✓ Statement 1: Valid")
fmt.Println("✗ Statement 2: Error E2002 - Expected FROM")
fmt.Println("✗ Statement 3: Error E2005 - Incomplete")
fmt.Println("✗ Statement 4: Syntax error - Missing comma")
fmt.Println("✗ Statement 5: Error E2003 - Missing INTO")
}
Example (ChainedErrors) ¶
Example_chainedErrors demonstrates error wrapping
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM users"
location := models.Location{Line: 1, Column: 1}
// Create a chain of errors
rootErr := errors.NewError(
errors.ErrCodeInvalidSyntax,
"invalid table reference",
location,
)
wrappedErr := errors.WrapError(
errors.ErrCodeUnexpectedToken,
"parser error",
location,
sql,
rootErr,
)
// Can unwrap to get root cause
if wrappedErr.Unwrap() == rootErr {
fmt.Println("Successfully wrapped error")
}
}
Output: Successfully wrapped error
Example (ComparingErrors) ¶
Example_comparingErrors demonstrates before and after error format
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FORM users"
location := models.Location{Line: 1, Column: 10}
fmt.Println("=== BEFORE: Simple Error ===")
fmt.Println("Error: expected FROM, got FORM")
fmt.Println()
fmt.Println("=== AFTER: Enhanced Error ===")
err := errors.ExpectedTokenError("FROM", "FORM", location, sql)
fmt.Println(err.Error())
fmt.Println()
fmt.Println("Enhancement includes:")
fmt.Println("✓ Error code (E2002)")
fmt.Println("✓ Precise location (line 1, column 10)")
fmt.Println("✓ SQL context with visual indicator")
fmt.Println("✓ Intelligent hint with typo detection")
fmt.Println("✓ Documentation link")
}
Example (ContextExtraction) ¶
Example_contextExtraction demonstrates SQL context in error messages
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
// Multi-line SQL with error on line 2
sql := `SELECT *
FROM users
WHERE age > 18.45.6
ORDER BY name`
location := models.Location{Line: 3, Column: 13}
err := errors.InvalidNumberError("18.45.6", location, sql)
// Error includes:
// - The problematic line from the SQL
// - Position indicator pointing to the error
// - Helpful hint about numeric format
fmt.Println("Error detected in multi-line SQL:")
_ = err // Use the error
}
Example (CustomHints) ¶
Example_customHints demonstrates adding custom hints
package main
import (
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM users WHERE"
location := models.Location{Line: 1, Column: 27}
err := errors.NewError(
errors.ErrCodeIncompleteStatement,
"incomplete WHERE clause",
location,
)
err.WithContext(sql, 5)
err.WithHint("Add a condition after WHERE, e.g., WHERE age > 18")
// Error now includes custom context and hint
_ = err
}
Example (CustomHintsEnhanced) ¶
Example_customHintsEnhanced demonstrates adding custom hints to errors
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM users WHERE age > '18'"
location := models.Location{Line: 1, Column: 33}
err := errors.NewError(
errors.ErrCodeInvalidSyntax,
"type mismatch in comparison",
location,
)
err.WithContext(sql, 4) // Highlight '18'
err.WithHint("Age comparisons should use numeric values without quotes. Change '18' to 18")
fmt.Println("Custom Hint Example:")
fmt.Println(err.Error())
fmt.Println()
}
Example (EnhancedErrorWithContext) ¶
Example_enhancedErrorWithContext demonstrates the enhanced error formatting with 3 lines of context
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
// Multi-line SQL with an error on line 3
sql := `SELECT id, name, email
FROM users
WHERE age > 18.45.6
ORDER BY name`
location := models.Location{Line: 3, Column: 13}
err := errors.InvalidNumberError("18.45.6", location, sql)
fmt.Println("Enhanced Error Output:")
fmt.Println(err.Error())
fmt.Println()
// Note: This will show:
// - Line 2 (FROM users)
// - Line 3 (WHERE age > 18.45.6) with error indicator
// - Line 4 (ORDER BY name)
}
Example (ErrorChaining) ¶
Example_errorChaining demonstrates wrapping errors
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM users"
location := models.Location{Line: 1, Column: 1}
// Create a chain of errors
rootErr := errors.NewError(
errors.ErrCodeInvalidSyntax,
"invalid table reference",
location,
)
wrappedErr := errors.WrapError(
errors.ErrCodeUnexpectedToken,
"parser error while processing SELECT",
location,
sql,
rootErr,
)
fmt.Println("Chained Error:")
fmt.Println(wrappedErr.Error())
fmt.Println()
// Can unwrap to get root cause
if wrappedErr.Unwrap() != nil {
fmt.Println("Root cause available through Unwrap()")
}
// Note: Output includes chained error with context
// Root cause available through Unwrap()
}
Example (ErrorCodeProgrammaticHandling) ¶
Example_errorCodeProgrammaticHandling demonstrates using error codes for logic
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM"
location := models.Location{Line: 1, Column: 14}
err := errors.IncompleteStatementError(location, sql)
// Check error type programmatically
if errors.IsCode(err, errors.ErrCodeIncompleteStatement) {
fmt.Println("Detected incomplete SQL statement")
fmt.Println("Error code:", errors.GetCode(err))
fmt.Println("Can suggest adding table name")
}
}
Output: Detected incomplete SQL statement Error code: E2005 Can suggest adding table name
Example (ErrorCodes) ¶
Example_errorCodes demonstrates programmatic error handling
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM"
location := models.Location{Line: 1, Column: 14}
// Create an error
err := errors.IncompleteStatementError(location, sql)
// Check error code programmatically
if errors.IsCode(err, errors.ErrCodeIncompleteStatement) {
fmt.Println("Detected incomplete SQL statement")
}
// Get error code
code := errors.GetCode(err)
fmt.Printf("Error code: %s\n", code)
}
Output: Detected incomplete SQL statement Error code: E2005
Example (ErrorRecovery) ¶
Example_errorRecovery demonstrates how to handle and recover from errors
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FORM users"
location := models.Location{Line: 1, Column: 10}
err := errors.ExpectedTokenError("FROM", "FORM", location, sql)
// Check if error is recoverable
if errors.IsCode(err, errors.ErrCodeExpectedToken) {
fmt.Println("Detected recoverable syntax error")
fmt.Println("Suggestion: Fix the typo and retry")
// Use the error's hint for auto-correction
if err.Hint != "" {
fmt.Println("Hint:", err.Hint)
}
}
}
Output: Detected recoverable syntax error Suggestion: Fix the typo and retry Hint: Did you mean 'FROM' instead of 'FORM'?
Example (IncompleteStatement) ¶
Example_incompleteStatement demonstrates incomplete SQL statement
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM users WHERE"
location := models.Location{Line: 1, Column: 26}
err := errors.IncompleteStatementError(location, sql)
fmt.Println("Incomplete Statement Example:")
fmt.Println(err.Error())
fmt.Println()
}
Example (InvalidNumber) ¶
Example_invalidNumber demonstrates invalid number format error
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM products WHERE price > 19.99.5"
location := models.Location{Line: 1, Column: 38}
err := errors.InvalidNumberError("19.99.5", location, sql)
fmt.Println("Invalid Number Example:")
fmt.Println(err.Error())
fmt.Println()
}
Example (MissingClause) ¶
Example_missingClause demonstrates missing clause error with suggestions
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT id, name, email users WHERE age > 18"
location := models.Location{Line: 1, Column: 24}
err := errors.MissingClauseError("FROM", location, sql)
fmt.Println("Missing Clause Example:")
fmt.Println(err.Error())
fmt.Println()
}
Example (MultiLineError) ¶
Example_multiLineError demonstrates error in multi-line SQL with proper context
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := `SELECT
u.id,
u.name,
u.email
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.age > 18.45.6
AND o.total > 100`
location := models.Location{Line: 7, Column: 15}
err := errors.InvalidNumberError("18.45.6", location, sql)
fmt.Println("Multi-line SQL Error:")
fmt.Println(err.Error())
fmt.Println()
// Shows context with proper line numbering:
// Line 6: JOIN orders o ON u.id = o.user_id
// Line 7: WHERE u.age > 18.45.6 <- Error indicator here
// Line 8: AND o.total > 100
}
Example (MultipleErrors) ¶
Example_multipleErrors demonstrates handling multiple validation errors
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
)
func main() {
queries := []string{
"SELECT * FORM users", // E2002: Expected FROM
"SELECT * FROM", // E2005: Incomplete statement
"SELECT * FROM users WHERE age >", // E2005: Incomplete expression
}
errorCodes := []errors.ErrorCode{}
for _, query := range queries {
// In real usage, you'd call gosqlx.Parse() here
// For this example, we'll simulate errors
_ = query
}
fmt.Printf("Found %d SQL errors\n", len(errorCodes))
}
Example (RealWorldScenario) ¶
Example_realWorldScenario demonstrates a complete real-world error scenario
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
// Simulate a real SQL query with multiple errors
sqlQueries := []struct {
sql string
location models.Location
errType string
}{
{
sql: "SELECT id, name email FROM users",
location: models.Location{Line: 1, Column: 17},
errType: "missing_comma",
},
{
sql: "SELECT * FROM users WHERE age > '18'",
location: models.Location{Line: 1, Column: 33},
errType: "string_instead_of_number",
},
{
sql: "SELECT * FROM users JOIN orders",
location: models.Location{Line: 1, Column: 25},
errType: "missing_join_condition",
},
}
fmt.Println("=== Real-World Error Scenarios ===")
fmt.Println()
for i, query := range sqlQueries {
fmt.Printf("Scenario %d: %s\n", i+1, query.errType)
fmt.Println("Query:", query.sql)
// In real usage, the parser would detect and create these errors
fmt.Println("(Error details would be shown here with full context and suggestions)")
fmt.Println()
}
}
Example (TypoDetection) ¶
Example_typoDetection demonstrates automatic typo detection
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
)
func main() {
// Common SQL keyword typos are automatically detected
// Using a slice to maintain predictable order
typos := []struct {
typo string
correct string
}{
{"FORM", "FROM"},
{"JION", "JOIN"},
{"SELCT", "SELECT"},
{"UPDTE", "UPDATE"},
{"WAHER", "WHERE"},
}
for _, t := range typos {
suggestion := errors.SuggestKeyword(t.typo)
if suggestion == t.correct {
fmt.Printf("%s → %s ✓\n", t.typo, suggestion)
}
}
}
Output: FORM → FROM ✓ JION → JOIN ✓ SELCT → SELECT ✓ UPDTE → UPDATE ✓ WAHER → WHERE ✓
Example (TypoDetectionWithSuggestions) ¶
Example_typoDetectionWithSuggestions demonstrates automatic typo detection
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
// Common SQL keyword typo
sql := "SELECT * FORM users WHERE age > 18"
location := models.Location{Line: 1, Column: 10}
err := errors.ExpectedTokenError("FROM", "FORM", location, sql)
fmt.Println("Typo Detection Example:")
fmt.Println(err.Error())
fmt.Println()
// The error will include:
// - Error code and location
// - SQL context with the typo highlighted
// - Intelligent hint: "Did you mean 'FROM' instead of 'FORM'?"
// - Help URL for documentation
}
Example (UnexpectedCharacter) ¶
Example_unexpectedCharacter demonstrates unexpected character in SQL
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM users WHERE age > 18 & active = 1"
location := models.Location{Line: 1, Column: 36}
err := errors.UnexpectedCharError('&', location, sql)
fmt.Println("Unexpected Character Example:")
fmt.Println(err.Error())
fmt.Println()
// Suggests: "Remove or escape the character '&'"
// User should use AND instead of &
}
Example (UnterminatedString) ¶
Example_unterminatedString demonstrates unterminated string error
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/errors"
"github.com/ajitpratap0/GoSQLX/pkg/models"
)
func main() {
sql := "SELECT * FROM users WHERE name = 'John"
location := models.Location{Line: 1, Column: 34}
err := errors.UnterminatedStringError(location, sql)
fmt.Println("Unterminated String Example:")
fmt.Println(err.Error())
fmt.Println()
}
Index ¶
- Variables
- func AnalyzeTokenError(tokenType, tokenValue, expectedType string) string
- func ClearSuggestionCache()
- func ExtractLocation(err error) (models.Location, bool)
- func FormatContextWindow(sql string, location models.Location, highlightLen int, ...) string
- func FormatErrorList(errors []*Error) string
- func FormatErrorSummary(err error) string
- func FormatErrorWithContext(err error, sql string) string
- func FormatErrorWithContextAt(code ErrorCode, message string, location models.Location, sql string, ...) string
- func FormatErrorWithExample(code ErrorCode, message string, location models.Location, sql string, ...) string
- func FormatErrorWithSuggestion(code ErrorCode, message string, location models.Location, sql string, ...) string
- func FormatMistakeExample(mistake MistakePattern) string
- func FormatMultiLineContext(sql string, location models.Location, highlightLen int) string
- func GenerateDidYouMean(actual string, possibleValues []string) string
- func GenerateHint(code ErrorCode, expected, found string) string
- func GetAdvancedFeatureHint(feature string) string
- func GetCommonHint(key string) string
- func IsCode(err error, code ErrorCode) bool
- func IsStructuredError(err error) bool
- func ResetSuggestionCacheStats()
- func SuggestForCTE(context string) string
- func SuggestForIncompleteStatement(lastKeyword string) string
- func SuggestForJoinError(joinType, context string) string
- func SuggestForSetOperation(operation, context string) string
- func SuggestForSyntaxError(context, expectedToken string) string
- func SuggestForWindowFunction(context, functionName string) string
- func SuggestFromPattern(errorMessage string) string
- func SuggestKeyword(input string) string
- func SuggestionCacheSize() int
- type Error
- func AmbiguousColumnError(columnName string, tables []string, location models.Location, sql string) *Error
- func ExpectedTokenError(expected, got string, location models.Location, sql string) *Error
- func IncompleteStatementError(location models.Location, sql string) *Error
- func InputTooLargeError(size, maxSize int64, location models.Location) *Error
- func InvalidCTEError(description string, location models.Location, sql string) *Error
- func InvalidNumberError(value string, location models.Location, sql string) *Error
- func InvalidSetOperationError(operation, description string, location models.Location, sql string) *Error
- func InvalidSyntaxError(description string, location models.Location, sql string) *Error
- func MissingClauseError(clause string, location models.Location, sql string) *Error
- func NewError(code ErrorCode, message string, location models.Location) *Error
- func RecursionDepthLimitError(depth, maxDepth int, location models.Location, sql string) *Error
- func TokenLimitReachedError(count, maxTokens int, location models.Location, sql string) *Error
- func TokenizerPanicError(panicValue interface{}, location models.Location) *Error
- func TypeMismatchError(leftType, rightType, context string, location models.Location, sql string) *Error
- func UndefinedColumnError(columnName, tableName string, location models.Location, sql string) *Error
- func UndefinedTableError(tableName string, location models.Location, sql string) *Error
- func UnexpectedCharError(char rune, location models.Location, sql string) *Error
- func UnexpectedTokenError(tokenType, tokenValue string, location models.Location, sql string) *Error
- func UnsupportedConstraintError(constraint string, location models.Location, sql string) *Error
- func UnsupportedDataTypeError(dataType string, location models.Location, sql string) *Error
- func UnsupportedFeatureError(feature string, location models.Location, sql string) *Error
- func UnsupportedJoinError(joinType string, location models.Location, sql string) *Error
- func UnterminatedBlockCommentError(location models.Location, sql string) *Error
- func UnterminatedStringError(location models.Location, sql string) *Error
- func WrapError(code ErrorCode, message string, location models.Location, sql string, ...) *Error
- type ErrorCode
- type ErrorContext
- type ErrorPattern
- type MistakePattern
- type SuggestionCacheStats
Examples ¶
- Package (AllErrorCodes)
- Package (BasicError)
- Package (BatchValidation)
- Package (ChainedErrors)
- Package (ComparingErrors)
- Package (ContextExtraction)
- Package (CustomHints)
- Package (CustomHintsEnhanced)
- Package (EnhancedErrorWithContext)
- Package (ErrorChaining)
- Package (ErrorCodeProgrammaticHandling)
- Package (ErrorCodes)
- Package (ErrorRecovery)
- Package (IncompleteStatement)
- Package (InvalidNumber)
- Package (MissingClause)
- Package (MultiLineError)
- Package (MultipleErrors)
- Package (RealWorldScenario)
- Package (TypoDetection)
- Package (TypoDetectionWithSuggestions)
- Package (UnexpectedCharacter)
- Package (UnterminatedString)
Constants ¶
This section is empty.
Variables ¶
var CommonHints = map[string]string{
"missing_from": "SELECT statements require a FROM clause unless selecting constants",
"missing_where": "Add a WHERE clause to filter the results",
"unclosed_paren": "Check that all parentheses are properly matched",
"missing_comma": "List items should be separated by commas",
"invalid_join": "JOIN clauses must include ON or USING conditions",
"duplicate_alias": "Each table alias must be unique within the query",
"ambiguous_column": "Qualify the column name with the table name or alias (e.g., table.column)",
}
CommonHints is a pre-built map of human-readable hint messages keyed by a short scenario identifier. The map covers the most frequent SQL authoring mistakes and is intended for use in error formatters that want to attach a contextual hint without invoking the full suggestion pipeline.
The available keys are:
"missing_from" — SELECT without a FROM clause "missing_where" — reminder to add a WHERE filter "unclosed_paren" — unbalanced parentheses "missing_comma" — list items not separated by commas "invalid_join" — JOIN clause missing ON or USING "duplicate_alias" — non-unique table alias "ambiguous_column" — unqualified column reference in multi-table query
Use GetCommonHint for safe lookup with a zero-value fallback.
Functions ¶
func AnalyzeTokenError ¶
AnalyzeTokenError produces a context-aware suggestion string for token-level parse errors. It inspects the actual and expected token types to provide specific guidance — for example, detecting when a quoted string is used where a number is expected, or when an unknown identifier looks like a misspelled keyword.
Parameters:
- tokenType: Type of the unexpected token (e.g., "STRING", "NUMBER", "IDENT")
- tokenValue: Raw text value of the unexpected token
- expectedType: Token type the parser was expecting (e.g., "NUMBER", "RPAREN")
Returns a human-readable suggestion string; never returns empty string.
func ClearSuggestionCache ¶ added in v1.6.0
func ClearSuggestionCache()
ClearSuggestionCache removes all entries from the keyword suggestion cache. Call this in tests to ensure a clean state between test cases, or after modifying the keyword list so that stale suggestions are not served.
func ExtractLocation ¶
ExtractLocation extracts the line/column location from a GoSQLX *Error. This is the preferred way to obtain location data for IDE integrations such as LSP diagnostics, since it handles the type assertion safely.
Returns the Location and true when err is a *Error; returns a zero Location and false for all other error types.
func FormatContextWindow ¶
func FormatContextWindow(sql string, location models.Location, highlightLen int, linesBefore, linesAfter int) string
FormatContextWindow formats a configurable SQL context window of up to linesBefore lines before and linesAfter lines after the error line. Prefer this over FormatMultiLineContext when more surrounding context is needed (e.g., in IDE hover messages or verbose diagnostic reports).
Parameters:
- sql: The full SQL source string
- location: The line/column of the error (1-based)
- highlightLen: Number of characters to highlight at the error column
- linesBefore: Number of source lines to display before the error line
- linesAfter: Number of source lines to display after the error line
Returns the formatted context block, or an empty string if location is invalid.
func FormatErrorList ¶
FormatErrorList formats a slice of structured errors into a numbered list with full context for each entry. The output begins with a count line and separates each error with a blank line.
Returns "No errors" when the slice is empty.
Parameters:
- errors: Slice of *Error values to format
Returns the multi-error report string.
func FormatErrorSummary ¶
FormatErrorSummary provides a concise one-line error summary suitable for structured logging and monitoring systems where a full context window would be too verbose. For *Error values the output format is:
[E2001] unexpected token: COMMA at line 5, column 20
For other error types the output is "Error: <message>".
Parameters:
- err: The error to summarise
Returns the one-line summary string.
func FormatErrorWithContext ¶
FormatErrorWithContext formats an error with SQL context and visual indicators. For *Error values it delegates to the structured Error.Error() method, which includes code, location, SQL context highlighting, hint, and help URL. For all other error types it falls back to a plain "Error: <message>" string.
Parameters:
- err: The error to format (may be *Error or a generic error)
- sql: The SQL source; currently unused for *Error (context is already attached)
Returns the formatted error string ready for display to end users.
func FormatErrorWithContextAt ¶
func FormatErrorWithContextAt(code ErrorCode, message string, location models.Location, sql string, highlightLen int) string
FormatErrorWithContextAt creates a structured error for the given code and location, attaches the SQL context window, and auto-generates a hint. It then returns the fully-formatted error string. This is useful for one-shot error formatting without retaining the *Error value.
Parameters:
- code: ErrorCode classifying the error category (e.g., ErrCodeExpectedToken)
- message: Human-readable description of the error
- location: Precise line/column where the error occurred
- sql: Full SQL source used to generate the context window
- highlightLen: Number of characters to highlight at the error column
Returns the complete formatted error string including context highlighting.
func FormatErrorWithExample ¶
func FormatErrorWithExample(code ErrorCode, message string, location models.Location, sql string, highlightLen int, wrongExample, correctExample string) string
FormatErrorWithExample formats an error and appends a side-by-side "Wrong / Correct" example to the hint. This is particularly useful for educational error messages (e.g., in linters or IDEs) where showing the correct pattern helps users learn the expected SQL syntax.
Parameters:
- code: ErrorCode classifying the error category
- message: Human-readable description of the error
- location: Precise line/column where the error occurred
- sql: Full SQL source used to generate the context window
- highlightLen: Number of characters to highlight at the error column
- wrongExample: The erroneous SQL fragment (e.g., "SELECT * FORM users")
- correctExample: The corrected SQL fragment (e.g., "SELECT * FROM users")
Returns the complete formatted error string including the before/after example.
func FormatErrorWithSuggestion ¶
func FormatErrorWithSuggestion(code ErrorCode, message string, location models.Location, sql string, highlightLen int, suggestion string) string
FormatErrorWithSuggestion creates and formats a structured error that includes a manually provided hint. When suggestion is empty, the function falls back to auto-generating a hint via GenerateHint. This is the preferred formatter when the caller already knows the correct fix.
Parameters:
- code: ErrorCode classifying the error category
- message: Human-readable description of the error
- location: Precise line/column where the error occurred
- sql: Full SQL source used to generate the context window
- highlightLen: Number of characters to highlight at the error column
- suggestion: Custom hint text; empty string triggers auto-generation
Returns the complete formatted error string.
func FormatMistakeExample ¶
func FormatMistakeExample(mistake MistakePattern) string
FormatMistakeExample formats a MistakePattern into a human-readable multi-line block suitable for displaying in error messages, documentation, or interactive tutorials. The output includes the mistake name, the wrong SQL snippet, the corrected SQL snippet, and an explanation.
Example output:
Common Mistake: missing_group_by Wrong: SELECT dept, COUNT(*) FROM employees Right: SELECT dept, COUNT(*) FROM employees GROUP BY dept Explanation: Non-aggregated columns in SELECT must appear in GROUP BY
func FormatMultiLineContext ¶
FormatMultiLineContext formats an SQL context window around a specific error location. It shows up to three lines: one before the error, the error line itself, and one after. A caret indicator (^) is rendered below the error column, with optional multi-character highlighting when highlightLen > 1.
Parameters:
- sql: The full SQL source string (may contain newlines)
- location: The line/column of the error (1-based)
- highlightLen: Number of characters to highlight; 1 renders a single caret
Returns the formatted context block, or an empty string if location is invalid.
func GenerateDidYouMean ¶
GenerateDidYouMean generates a "Did you mean?" suggestion by finding the closest match(es) to actual in possibleValues using Levenshtein distance. It only returns a suggestion when the edit distance is within half the length of actual (minimum threshold of 2), preventing spurious suggestions for completely unrelated words.
Parameters:
- actual: The misspelled or unrecognised word entered by the user
- possibleValues: Candidate correct values to compare against
Returns a suggestion string, or empty string if no close match is found.
func GenerateHint ¶
GenerateHint generates an actionable hint message tailored to the error code and the tokens involved. For token-mismatch errors it applies SuggestKeyword to detect typos and produces a "Did you mean?" message. For structural errors such as missing clauses or unsupported features it returns a generic guidance string.
Parameters:
- code: The ErrorCode that identifies the class of error (e.g., ErrCodeExpectedToken)
- expected: The token or keyword that was required (used for ErrCodeExpectedToken and ErrCodeMissingClause messages)
- found: The token that was actually present (used for typo detection)
Returns an empty string for error codes that have no pre-defined hint.
func GetAdvancedFeatureHint ¶
GetAdvancedFeatureHint returns a brief description and usage hint for an advanced SQL feature. Supported feature keys include: "window_functions", "cte", "recursive_cte", "set_operations", "window_frames", "partition_by", "lateral_join", and "grouping_sets".
The feature name is normalised to lowercase with spaces replaced by underscores before lookup. Returns a generic documentation link if the feature is not found.
func GetCommonHint ¶
GetCommonHint retrieves a pre-defined hint message from CommonHints by its scenario key. This is the safe alternative to indexing the map directly; it returns an empty string instead of the zero value when the key is absent, making nil-check patterns unnecessary in callers.
See CommonHints for the full list of valid keys.
func IsCode ¶
IsCode checks if an error has a specific error code.
Type-safe way to check error codes for programmatic error handling. Works with both *Error and other error types (returns false for non-Error).
Parameters:
- err: The error to check
- code: The ErrorCode to match against
Returns true if err is a *Error with matching code, false otherwise.
Example:
if errors.IsCode(err, errors.ErrCodeUnterminatedString) {
// Handle unterminated string error specifically
}
if errors.IsCode(err, errors.ErrCodeExpectedToken) {
// Handle expected token error
}
Common pattern:
switch {
case errors.IsCode(err, errors.ErrCodeUnexpectedToken):
// Handle unexpected token
case errors.IsCode(err, errors.ErrCodeMissingClause):
// Handle missing clause
default:
// Handle other errors
}
func IsStructuredError ¶
IsStructuredError reports whether err is a GoSQLX *Error value. Use this to distinguish GoSQLX structured errors from generic Go errors before calling functions that require *Error (e.g., ExtractLocation).
Example:
if errors.IsStructuredError(err) {
loc, _ := errors.ExtractLocation(err)
// use loc for IDE diagnostics
}
func ResetSuggestionCacheStats ¶ added in v1.6.0
func ResetSuggestionCacheStats()
ResetSuggestionCacheStats zeroes all hit, miss, and eviction counters in the keyword suggestion cache without clearing cached entries. Call this at the start of a benchmark or monitoring interval to obtain a clean measurement window.
func SuggestForCTE ¶
SuggestForCTE provides targeted suggestions for Common Table Expression (WITH clause) syntax errors. It detects problems such as a WITH clause not followed by a DML statement, a RECURSIVE CTE missing UNION, or multiple CTEs not separated by commas.
Parameters:
- context: A SQL snippet containing the WITH clause and surrounding context
Returns a specific remediation hint for the detected problem.
func SuggestForIncompleteStatement ¶
SuggestForIncompleteStatement returns a suggestion string explaining what tokens or clauses are expected to follow the given SQL keyword. This is used when the parser encounters an unexpected end-of-input after a keyword.
Parameters:
- lastKeyword: The last SQL keyword seen before end-of-input (e.g., "SELECT", "FROM")
Returns the context-appropriate completion hint, or a generic fallback message.
func SuggestForJoinError ¶
SuggestForJoinError provides targeted suggestions for JOIN syntax errors. It detects missing ON or USING conditions (noting that CROSS JOIN is the sole exception) and ambiguous column references in join conditions.
Parameters:
- joinType: The JOIN type keyword (e.g., "INNER", "LEFT", "CROSS")
- context: A SQL snippet containing the JOIN clause
Returns a specific remediation hint for the detected problem.
func SuggestForSetOperation ¶
SuggestForSetOperation provides targeted suggestions for UNION, INTERSECT, and EXCEPT syntax errors. It detects ORDER BY inside a subquery (which should be after the full set operation) and column count/type mismatches.
Parameters:
- operation: The set operation keyword (e.g., "UNION", "INTERSECT", "EXCEPT")
- context: A SQL snippet containing the set operation
Returns a specific remediation hint for the detected problem.
func SuggestForSyntaxError ¶
SuggestForSyntaxError returns a context-aware suggestion string for a syntax error. It inspects the surrounding SQL context (e.g., whether a SELECT or JOIN keyword is present) and the expected token to provide targeted guidance.
Parameters:
- context: A snippet of the SQL surrounding the error (used for keyword detection)
- expectedToken: The token or clause that was expected (e.g., "FROM", ",", "ON")
Returns a human-readable hint specific to the context, or a generic fallback.
func SuggestForWindowFunction ¶
SuggestForWindowFunction provides targeted suggestions for window function syntax errors. It inspects the SQL context to detect common mistakes such as a missing OVER clause, PARTITION BY outside OVER, or a window frame without ORDER BY.
Parameters:
- context: A SQL snippet containing the window function usage
- functionName: The name of the window function (e.g., "ROW_NUMBER", "SUM")
Returns a specific remediation hint for the detected problem.
func SuggestFromPattern ¶
SuggestFromPattern tries to match an error message string against the built-in errorPatterns catalogue and returns the associated suggestion. This is useful for augmenting generic error messages with actionable advice without re-parsing the original SQL.
Returns the suggestion string if a pattern matches, or empty string if none match.
func SuggestKeyword ¶
SuggestKeyword uses Levenshtein distance to suggest the closest SQL keyword matching the given input token. The suggestion is only returned when the edit distance is within half the length of the input (minimum threshold of 2), which prevents semantically unrelated tokens from being suggested.
Results are stored in a bounded LRU-style cache shared across all calls to improve performance during repeated error-reporting scenarios where the same misspelled token appears many times (e.g., in batch query validation).
Returns the matching keyword in uppercase, or an empty string if no sufficiently close match is found.
func SuggestionCacheSize ¶ added in v1.6.0
func SuggestionCacheSize() int
SuggestionCacheSize returns the number of entries currently held in the keyword suggestion cache. Use this for monitoring cache growth and deciding whether to adjust the maximum size.
Types ¶
type Error ¶
type Error struct {
Code ErrorCode // Unique error code (e.g., "E2001")
Message string // Human-readable error message
Location models.Location // Line and column where error occurred
Context *ErrorContext // SQL context around the error
Hint string // Suggestion to fix the error
HelpURL string // Documentation link for this error
Cause error // Underlying error if any
}
Error represents a structured error with rich context and hints.
Error is the main error type in GoSQLX, providing comprehensive information for debugging and user feedback. It includes error codes, precise locations, SQL context with highlighting, intelligent hints, and help URLs.
Fields:
- Code: Unique error identifier (E1xxx-E4xxx) for programmatic handling
- Message: Human-readable error description
- Location: Precise line/column where error occurred (1-based)
- Context: SQL source context with highlighting (optional)
- Hint: Auto-generated suggestion to fix the error (optional)
- HelpURL: Documentation link for this error code
- Cause: Underlying error if wrapped (optional)
Example creation:
err := errors.NewError(
errors.ErrCodeUnexpectedToken,
"unexpected token: COMMA",
models.Location{Line: 5, Column: 20},
)
err = err.WithContext(sqlSource, 1)
err = err.WithHint("Expected FROM keyword after SELECT clause")
Error output format:
Error E2001 at line 5, column 20: unexpected token: COMMA
4 | SELECT name, email
5 | FROM users, WHERE active = true
^^^^
6 |
Hint: Expected FROM keyword after SELECT clause
Help: https://github.com/ajitpratap0/GoSQLX/blob/main/docs/ERROR_CODES.md
Thread Safety: Error instances are immutable after creation. Methods like WithContext, WithHint return new Error instances and are safe for concurrent use.
func AmbiguousColumnError ¶ added in v1.6.0
func AmbiguousColumnError(columnName string, tables []string, location models.Location, sql string) *Error
AmbiguousColumnError creates an E3004 error when a column name appears in more than one table in scope and no qualifier disambiguates it. The hint suggests qualifying the column with a table name or alias.
Parameters:
- columnName: The ambiguous column name
- tables: Slice of table names that all contain the column (may be empty if unknown)
- location: Line/column where the ambiguous reference was found
- sql: Full SQL source used to generate visual context
func ExpectedTokenError ¶
ExpectedTokenError creates an E2002 error when a required token is absent or a different token appears in its place. The builder applies Levenshtein-based typo detection and auto-generates a "Did you mean?" hint when the found token is close to the expected one (e.g., FORM vs FROM).
Parameters:
- expected: The token or keyword that was required (e.g., "FROM")
- got: The token or keyword that was actually found (e.g., "FORM")
- location: Line/column where the mismatch occurred
- sql: Full SQL source used to generate visual context
func IncompleteStatementError ¶
IncompleteStatementError creates an E2005 error when the parser reaches the end of input before a SQL statement is complete. This typically means a clause or closing parenthesis is missing.
Parameters:
- location: Line/column at end-of-input where parsing stopped
- sql: Full SQL source used to generate visual context
func InputTooLargeError ¶
InputTooLargeError creates an E1006 error when the SQL input exceeds the configured maximum byte size. This protects against denial-of-service attacks that submit extremely large SQL strings. The hint advises reducing input or adjusting the MaxInputSize configuration.
Parameters:
- size: Actual input size in bytes
- maxSize: Configured maximum size in bytes
- location: Typically the beginning of input (line 1, column 1)
func InvalidCTEError ¶
InvalidCTEError creates an E2011 error for malformed Common Table Expression (WITH clause) syntax. Common causes include a missing AS keyword, missing parentheses around the CTE body, or a missing trailing SELECT statement.
Parameters:
- description: Explanation of the specific CTE syntax problem
- location: Line/column where the CTE syntax error was detected
- sql: Full SQL source used to generate visual context
func InvalidNumberError ¶
InvalidNumberError creates an E1003 error for a malformed numeric literal, such as a number with multiple decimal points (1.2.3) or an invalid exponent format.
Parameters:
- value: The raw string that could not be parsed as a number
- location: Line/column where the literal starts
- sql: Full SQL source used to generate visual context
func InvalidSetOperationError ¶
func InvalidSetOperationError(operation, description string, location models.Location, sql string) *Error
InvalidSetOperationError creates an E2012 error for an invalid UNION, INTERSECT, or EXCEPT set operation. The most common cause is a column count or type mismatch between the left and right queries.
Parameters:
- operation: The set operation keyword (e.g., "UNION", "INTERSECT")
- description: Explanation of why the operation is invalid
- location: Line/column where the set operation was found
- sql: Full SQL source used to generate visual context
func InvalidSyntaxError ¶
InvalidSyntaxError creates an E2004 general syntax error for violations that do not match any more specific error code. Use more specific builder functions (e.g., ExpectedTokenError, MissingClauseError) when possible for better diagnostics.
Parameters:
- description: Free-form description of the syntax problem
- location: Line/column where the violation was detected
- sql: Full SQL source used to generate visual context
func MissingClauseError ¶
MissingClauseError creates an E2003 error when a required SQL clause is absent. For example, a SELECT statement without a FROM clause, or a JOIN without an ON condition. A pre-built hint from CommonHints is used if available.
Parameters:
- clause: Name of the missing clause (e.g., "FROM", "ON")
- location: Line/column where the clause should have appeared
- sql: Full SQL source used to generate visual context
func NewError ¶
NewError creates a new structured error.
Factory function for creating GoSQLX errors with error code, message, and location. This is the primary way to create errors in the library.
Parameters:
- code: ErrorCode for programmatic error handling (E1xxx-E4xxx)
- message: Human-readable error description
- location: Precise line/column where error occurred
Returns a new Error with the specified fields and auto-generated help URL.
Example:
err := errors.NewError(
errors.ErrCodeUnexpectedToken,
"unexpected token: COMMA",
models.Location{Line: 5, Column: 20},
)
// err.HelpURL is automatically set to https://github.com/ajitpratap0/GoSQLX/blob/main/docs/ERROR_CODES.md
The error can be enhanced with additional context:
err = err.WithContext(sqlSource, 1).WithHint("Expected FROM keyword")
func RecursionDepthLimitError ¶
RecursionDepthLimitError creates an E2007 error when the parser's recursion counter exceeds the configured maximum. This guards against deeply nested subqueries and expressions that could exhaust the call stack. The hint suggests simplifying the query structure.
Parameters:
- depth: Current recursion depth when the limit was reached
- maxDepth: Configured maximum recursion depth
- location: Position in SQL where the depth limit was triggered
- sql: Full SQL source used to generate visual context
func TokenLimitReachedError ¶
TokenLimitReachedError creates an E1007 error when the number of tokens produced by the tokenizer exceeds the configured maximum. This protects against pathological SQL that generates an excessive token stream. The hint suggests simplifying the query or raising the MaxTokens limit.
Parameters:
- count: Actual number of tokens produced
- maxTokens: Configured token count limit
- location: Position in SQL where the limit was hit
- sql: Full SQL source used to generate visual context
func TokenizerPanicError ¶
TokenizerPanicError creates an E1008 error for a panic that was recovered inside the tokenizer. This signals a tokenizer implementation bug rather than a user input problem. The hint asks the user to report the issue.
Parameters:
- panicValue: The value recovered from the panic (may be an error or string)
- location: Position in SQL at the time of the panic
func TypeMismatchError ¶ added in v1.6.0
func TypeMismatchError(leftType, rightType, context string, location models.Location, sql string) *Error
TypeMismatchError creates an E3003 error when two sides of an expression have incompatible types (e.g., comparing an INTEGER column to a TEXT literal without a CAST). When context is non-empty, it is included in the message for clarity.
Parameters:
- leftType: Data type of the left operand (e.g., "INTEGER")
- rightType: Data type of the right operand (e.g., "TEXT")
- context: Optional description of where the mismatch occurs (e.g., "WHERE clause")
- location: Line/column where the type mismatch was detected
- sql: Full SQL source used to generate visual context
func UndefinedColumnError ¶ added in v1.6.0
func UndefinedColumnError(columnName, tableName string, location models.Location, sql string) *Error
UndefinedColumnError creates an E3002 error when a column name cannot be found in the referenced table's schema. When tableName is non-empty, the error message includes the table context for clearer diagnosis.
Parameters:
- columnName: The unresolved column name
- tableName: The table where the column was expected (empty if unknown)
- location: Line/column where the column reference was found
- sql: Full SQL source used to generate visual context
func UndefinedTableError ¶ added in v1.6.0
UndefinedTableError creates an E3001 error when a table name referenced in the query cannot be resolved in the available schema. The hint suggests checking for typos and verifying the table exists.
Parameters:
- tableName: The unresolved table name
- location: Line/column where the table reference was found
- sql: Full SQL source used to generate visual context
func UnexpectedCharError ¶
UnexpectedCharError creates an E1001 error for an unexpected character encountered during tokenization. The hint instructs the caller to remove or escape the character.
Parameters:
- char: The invalid character found in the SQL input
- location: Line/column where the character appears
- sql: Full SQL source used to generate visual context
func UnexpectedTokenError ¶
func UnexpectedTokenError(tokenType, tokenValue string, location models.Location, sql string) *Error
UnexpectedTokenError creates an E2001 error for a token that does not fit the expected grammar at the current parse position. An intelligent "Did you mean?" hint is auto-generated using Levenshtein distance when the token resembles a known SQL keyword.
Parameters:
- tokenType: The type of the unexpected token (e.g., "IDENT", "COMMA")
- tokenValue: The raw text of the token (empty string if not applicable)
- location: Line/column where the token was found
- sql: Full SQL source used to generate visual context
func UnsupportedConstraintError ¶
UnsupportedConstraintError creates an E2009 error when a table constraint type is present in the SQL but not yet handled by the parser. Supported constraints are PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL, and CHECK.
Parameters:
- constraint: The unrecognised constraint type (e.g., "EXCLUDE")
- location: Line/column where the constraint was found
- sql: Full SQL source used to generate visual context
func UnsupportedDataTypeError ¶
UnsupportedDataTypeError creates an E2008 error when the parser encounters a column data type that GoSQLX does not yet support. Supported types include INTEGER, VARCHAR, TEXT, and TIMESTAMP.
Parameters:
- dataType: The unrecognised data type string (e.g., "GEOMETRY", "JSONB")
- location: Line/column where the type token was found
- sql: Full SQL source used to generate visual context
func UnsupportedFeatureError ¶
UnsupportedFeatureError creates an E4001 error when the parser encounters a valid SQL construct that is recognised but not yet implemented. This distinguishes "not supported" from a syntax error so callers can handle the two cases separately.
Parameters:
- feature: Name or description of the unsupported feature (e.g., "LATERAL JOIN")
- location: Line/column where the feature was encountered
- sql: Full SQL source used to generate visual context
func UnsupportedJoinError ¶
UnsupportedJoinError creates an E2010 error for a JOIN type that the parser recognises syntactically but does not yet fully support. Supported join types are INNER, LEFT, RIGHT, FULL, CROSS, and NATURAL.
Parameters:
- joinType: The unrecognised or unsupported join type string
- location: Line/column where the join type token was found
- sql: Full SQL source used to generate visual context
func UnterminatedBlockCommentError ¶ added in v1.9.3
UnterminatedBlockCommentError creates an E1009 error for a block comment that was opened with /* but never closed with */. The hint guides the caller to add the missing closing delimiter.
Parameters:
- location: Line/column where the /* opening was found
- sql: Full SQL source used to generate visual context
func UnterminatedStringError ¶
UnterminatedStringError creates an E1002 error for an unterminated string literal. A string literal is considered unterminated when the tokenizer reaches end-of-input before finding the matching closing quote character.
Parameters:
- location: Line/column where the opening quote was found
- sql: Full SQL source used to generate visual context
func WrapError ¶
func WrapError(code ErrorCode, message string, location models.Location, sql string, cause error) *Error
WrapError creates a structured error that wraps an existing cause error. Use this to add error code, location, and SQL context to low-level errors (e.g., I/O errors, unexpected runtime panics) so they integrate with the GoSQLX error handling pipeline.
Parameters:
- code: ErrorCode classifying the error category
- message: Human-readable description of what went wrong
- location: Line/column in the SQL where the problem occurred
- sql: Full SQL source used to generate visual context
- cause: Underlying error being wrapped (accessible via errors.Is / errors.As)
func (*Error) Error ¶
Error implements the error interface.
Returns a formatted error message including:
- Error code and location (line/column)
- Error message
- SQL context with visual highlighting (if available)
- Hint/suggestion (if available)
- Help URL for documentation
Example output:
Error E2002 at line 1, column 15: expected FROM, got FORM
1 | SELECT * FORM users WHERE id = 1
^^^^
Hint: Did you mean 'FROM' instead of 'FORM'?
Help: https://github.com/ajitpratap0/GoSQLX/blob/main/docs/ERROR_CODES.md
This method is called automatically when the error is printed or logged.
func (*Error) Unwrap ¶
Unwrap returns the underlying error.
Implements error unwrapping for Go 1.13+ error chains. This allows errors.Is and errors.As to work with wrapped errors.
Example:
originalErr := someFunc()
wrappedErr := errors.NewError(...).WithCause(originalErr)
if errors.Is(wrappedErr, originalErr) {
// Can check for original error
}
func (*Error) WithCause ¶
WithCause adds an underlying cause error.
Wraps another error as the cause of this error, enabling error chaining and unwrapping with errors.Is and errors.As.
Parameters:
- cause: The underlying error that caused this error
Returns the same Error instance with cause added (for method chaining).
Example:
ioErr := os.ReadFile(filename) // Returns error
err := errors.NewError(
errors.ErrCodeInvalidSyntax,
"failed to read SQL file",
location,
).WithCause(ioErr)
// Check for original error
if errors.Is(err, os.ErrNotExist) {
// Handle file not found
}
Note: WithCause modifies the error in-place and returns it for chaining.
func (*Error) WithContext ¶
WithContext adds SQL context to the error.
Attaches SQL source code context with highlighting information for visual error display. The context shows surrounding lines and highlights the specific location of the error.
Parameters:
- sql: Original SQL source code
- highlightLen: Number of characters to highlight (starting at error column)
Returns the same Error instance with context added (for method chaining).
Example:
err := errors.NewError(code, "error message", location)
err = err.WithContext("SELECT * FORM users", 4) // Highlight "FORM"
The context will be displayed as:
1 | SELECT * FORM users
^^^^
Note: WithContext modifies the error in-place and returns it for chaining.
func (*Error) WithHint ¶
WithHint adds a suggestion hint to the error.
Attaches a helpful suggestion for fixing the error. Hints are generated automatically by builder functions or can be added manually.
Parameters:
- hint: Suggestion text (e.g., "Did you mean 'FROM' instead of 'FORM'?")
Returns the same Error instance with hint added (for method chaining).
Example:
err := errors.NewError(code, "message", location)
err = err.WithHint("Expected FROM keyword after SELECT clause")
Auto-generated hints:
err := errors.ExpectedTokenError("FROM", "FORM", location, sql)
// Automatically includes: "Did you mean 'FROM' instead of 'FORM'?"
Note: WithHint modifies the error in-place and returns it for chaining.
type ErrorCode ¶
type ErrorCode string
ErrorCode represents a unique error code for programmatic handling.
ErrorCode is a strongly-typed string for error classification. It enables programmatic error handling, filtering, and logging in production systems.
Error codes follow the pattern: E[category][number]
- E1xxx: Tokenizer/lexical errors
- E2xxx: Parser/syntax errors
- E3xxx: Semantic errors
- E4xxx: Unsupported features
Example usage:
err := errors.NewError(errors.ErrCodeUnexpectedToken, "msg", location)
if errors.IsCode(err, errors.ErrCodeUnexpectedToken) {
// Handle unexpected token error specifically
}
code := errors.GetCode(err)
switch code {
case errors.ErrCodeExpectedToken:
// Handle syntax errors
case errors.ErrCodeUndefinedTable:
// Handle semantic errors
}
const ( // E1xxx: Tokenizer errors ErrCodeUnexpectedChar ErrorCode = "E1001" // Unexpected character in input ErrCodeUnterminatedString ErrorCode = "E1002" // String literal not closed ErrCodeInvalidNumber ErrorCode = "E1003" // Invalid numeric literal ErrCodeInvalidOperator ErrorCode = "E1004" // Invalid operator sequence ErrCodeInvalidIdentifier ErrorCode = "E1005" // Invalid identifier format ErrCodeInputTooLarge ErrorCode = "E1006" // Input exceeds size limits (DoS protection) ErrCodeTokenLimitReached ErrorCode = "E1007" // Token count exceeds limit (DoS protection) ErrCodeTokenizerPanic ErrorCode = "E1008" // Tokenizer panic recovered ErrCodeUnterminatedBlockComment ErrorCode = "E1009" // Block comment not closed // E2xxx: Parser syntax errors ErrCodeUnexpectedToken ErrorCode = "E2001" // Unexpected token encountered ErrCodeExpectedToken ErrorCode = "E2002" // Expected specific token not found ErrCodeMissingClause ErrorCode = "E2003" // Required SQL clause missing ErrCodeInvalidSyntax ErrorCode = "E2004" // General syntax error ErrCodeIncompleteStatement ErrorCode = "E2005" // Statement incomplete ErrCodeInvalidExpression ErrorCode = "E2006" // Invalid expression syntax ErrCodeRecursionDepthLimit ErrorCode = "E2007" // Recursion depth exceeded (DoS protection) ErrCodeUnsupportedDataType ErrorCode = "E2008" // Data type not supported ErrCodeUnsupportedConstraint ErrorCode = "E2009" // Constraint type not supported ErrCodeUnsupportedJoin ErrorCode = "E2010" // JOIN type not supported ErrCodeInvalidCTE ErrorCode = "E2011" // Invalid CTE (WITH clause) syntax ErrCodeInvalidSetOperation ErrorCode = "E2012" // Invalid set operation (UNION/EXCEPT/INTERSECT) // E3xxx: Semantic errors ErrCodeUndefinedTable ErrorCode = "E3001" // Table not defined ErrCodeUndefinedColumn ErrorCode = "E3002" // Column not defined ErrCodeTypeMismatch ErrorCode = "E3003" // Type mismatch in expression ErrCodeAmbiguousColumn ErrorCode = "E3004" // Ambiguous column reference // E4xxx: Unsupported features ErrCodeUnsupportedFeature ErrorCode = "E4001" // Feature not yet supported ErrCodeUnsupportedDialect ErrorCode = "E4002" // SQL dialect not supported )
Error code categories
func ExtractErrorCode ¶
ExtractErrorCode extracts the ErrorCode from a GoSQLX *Error. Unlike GetCode, this function returns a boolean indicating whether the extraction succeeded, making it suitable for use in type-switch–style handling.
Returns the ErrorCode and true when err is a *Error; returns an empty string and false for all other error types.
func GetCode ¶
GetCode returns the error code from an error, or empty string if not a structured error.
Extracts the ErrorCode from a *Error. Returns empty string for non-Error types.
Parameters:
- err: The error to extract code from
Returns the ErrorCode if err is a *Error, empty string otherwise.
Example:
code := errors.GetCode(err)
switch code {
case errors.ErrCodeExpectedToken:
// Handle syntax errors
case errors.ErrCodeUndefinedTable:
// Handle semantic errors
case "":
// Not a structured error
}
Logging example:
if code := errors.GetCode(err); code != "" {
log.Printf("SQL error [%s]: %v", code, err)
}
type ErrorContext ¶
type ErrorContext struct {
SQL string // Original SQL query
StartLine int // Starting line number (1-indexed)
EndLine int // Ending line number (1-indexed)
HighlightCol int // Column to highlight (1-indexed)
HighlightLen int // Length of highlight (number of characters)
}
ErrorContext contains the SQL source and position information for display.
ErrorContext provides the SQL source code context around an error with precise highlighting information. Used to generate visual error displays with line numbers and position indicators.
Fields:
- SQL: Original SQL query source code
- StartLine: First line to display in context (1-based)
- EndLine: Last line to display in context (1-based)
- HighlightCol: Column to start highlighting (1-based)
- HighlightLen: Number of characters to highlight
Example:
ctx := &errors.ErrorContext{
SQL: "SELECT * FORM users",
StartLine: 1,
EndLine: 1,
HighlightCol: 10,
HighlightLen: 4, // Highlight "FORM"
}
The context is displayed as:
1 | SELECT * FORM users
^^^^
type ErrorPattern ¶
ErrorPattern represents a common SQL error pattern with an associated suggestion. Each pattern matches error messages (not raw SQL) and provides a human-readable hint for fixing the underlying mistake.
Fields:
- Pattern: Compiled regular expression matched against error message text
- Description: Short label for the pattern (used in documentation)
- Suggestion: Actionable fix advice to show to the user
type MistakePattern ¶
type MistakePattern struct {
Name string
Example string // Example of the mistake
Correct string // Correct version
Explanation string
}
MistakePattern represents a catalogued SQL coding mistake together with a corrected example and a plain-language explanation. The catalogue covers 20+ common mistakes including aggregate misuse, window function syntax, CTE problems, and set operation mismatches.
Fields:
- Name: Machine-readable key used to look up the pattern (e.g., "missing_group_by")
- Example: A minimal SQL fragment that demonstrates the mistake
- Correct: The corrected version of the same fragment
- Explanation: Human-readable explanation of why Example is wrong and Correct is right
func GetMistakeExplanation ¶
func GetMistakeExplanation(mistakeName string) (MistakePattern, bool)
GetMistakeExplanation looks up a MistakePattern by its machine-readable name. Use this to retrieve full before/after examples and explanations for known SQL anti-patterns. The name must exactly match one of the keys in the commonMistakes catalogue (e.g., "missing_group_by", "window_function_without_over").
Returns the matching MistakePattern and true, or a zero value and false when the name is not found.
type SuggestionCacheStats ¶ added in v1.6.0
type SuggestionCacheStats struct {
Size int
MaxSize int
Hits uint64
Misses uint64
Evictions uint64
HitRate float64
}
SuggestionCacheStats holds observability metrics for the keyword suggestion cache. Retrieve an instance via GetSuggestionCacheStats and reset counters via ResetSuggestionCacheStats.
Fields:
- Size: Current number of entries in the cache
- MaxSize: Configured maximum capacity (default 1000)
- Hits: Number of cache lookups that returned a cached value
- Misses: Number of cache lookups that required computing a new suggestion
- Evictions: Total number of entries removed during partial eviction sweeps
- HitRate: Ratio of Hits to (Hits + Misses); 0.0 when no lookups have occurred
func GetSuggestionCacheStats ¶ added in v1.6.0
func GetSuggestionCacheStats() SuggestionCacheStats
GetSuggestionCacheStats returns a snapshot of the current keyword suggestion cache metrics. The returned struct is safe to read without any additional locking. Use this in observability dashboards or benchmarks to track cache efficiency.
Example:
stats := errors.GetSuggestionCacheStats()
fmt.Printf("Cache hit rate: %.1f%%\n", stats.HitRate*100)