Documentation
¶
Overview ¶
Package gosqlx provides convenient high-level functions for SQL parsing and extraction.
Parser Limitations ¶
The extraction functions in this package are subject to the following parser limitations. These limitations represent SQL features that are partially supported or not yet fully implemented in the GoSQLX parser. As the parser evolves, these limitations may be addressed in future releases.
## Known Limitations
CASE Expressions: CASE expressions (simple and searched CASE) are not fully supported in the parser. Column references within CASE WHEN conditions and result expressions may not be extracted correctly.
Example (not fully supported): SELECT CASE status WHEN 'active' THEN name ELSE 'N/A' END FROM users
CAST Expressions: CAST expressions for type conversion are not fully supported. Column references within CAST expressions may not be extracted.
Example (not fully supported): SELECT CAST(price AS DECIMAL(10,2)) FROM products
IN Expressions: IN expressions with subqueries or complex value lists in WHERE clauses are not fully supported. Column references in IN lists may not be extracted correctly.
Example (not fully supported): SELECT * FROM users WHERE status IN ('active', 'pending') SELECT * FROM orders WHERE user_id IN (SELECT id FROM users)
BETWEEN Expressions: BETWEEN expressions for range comparisons are not fully supported. Column references in BETWEEN bounds may not be extracted correctly.
Example (not fully supported): SELECT * FROM products WHERE price BETWEEN min_price AND max_price
Schema-Qualified Table Names: Schema-qualified table names (schema.table format) are not fully supported by the parser. Tables with explicit schema qualifiers may not be parsed correctly.
Example (not fully supported): SELECT * FROM public.users JOIN app.orders ON users.id = orders.user_id
Complex Recursive CTEs: Recursive Common Table Expressions (CTEs) with complex JOIN syntax are not fully supported. Simple recursive CTEs work, but complex variations may fail to parse.
Example (not fully supported): WITH RECURSIVE org_chart AS ( SELECT id, name, manager_id, 1 as level FROM employees WHERE manager_id IS NULL UNION ALL SELECT e.id, e.name, e.manager_id, o.level + 1 FROM employees e INNER JOIN org_chart o ON e.manager_id = o.id ) SELECT * FROM org_chart
## Workarounds
For queries using these unsupported features:
- Simplify complex expressions where possible
- Use alternative SQL syntax that is supported
- Extract metadata manually from the original SQL string
- Consider contributing parser enhancements to the GoSQLX project
## Reporting Issues
If you encounter parsing issues with SQL queries that should be supported, please report them at: https://github.com/ajitpratap0/GoSQLX/issues
Package gosqlx provides convenient high-level functions for SQL parsing.
This package wraps the lower-level tokenizer and parser APIs to provide a simple, ergonomic interface for common operations. All object pool management is handled internally.
For performance-critical applications that need fine-grained control, use the lower-level APIs in pkg/sql/tokenizer and pkg/sql/parser directly.
Example (AdvancedFeatures) ¶
Example_advancedFeatures demonstrates parsing advanced SQL features.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
// Window functions
windowSQL := "SELECT name, ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) as rank FROM employees"
ast1, err := gosqlx.Parse(windowSQL)
if err != nil {
log.Fatal(err)
}
// CTEs
cteSQL := "WITH active AS (SELECT * FROM users WHERE active = true) SELECT * FROM active"
ast2, err := gosqlx.Parse(cteSQL)
if err != nil {
log.Fatal(err)
}
// JOINs
joinSQL := "SELECT u.name, o.total FROM users u INNER JOIN orders o ON u.id = o.user_id"
ast3, err := gosqlx.Parse(joinSQL)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed window: %d, CTE: %d, JOIN: %d\n", len(ast1.Statements), len(ast2.Statements), len(ast3.Statements))
}
Output: Parsed window: 1, CTE: 1, JOIN: 1
Example (AnalyzeQuery) ¶
Example_analyzeQuery demonstrates using extraction for query analysis.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := `SELECT
u.username,
COUNT(o.id) as total_orders,
SUM(o.amount) as total_spent,
UPPER(u.email) as email_upper
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.active = true AND o.status = 'completed'
GROUP BY u.id, u.username, u.email
HAVING COUNT(o.id) > 10
ORDER BY total_spent DESC`
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
metadata := gosqlx.ExtractMetadata(ast)
fmt.Printf("Query Analysis:\n")
fmt.Printf("- Joins %d tables\n", len(metadata.Tables))
fmt.Printf("- References %d columns\n", len(metadata.Columns))
fmt.Printf("- Uses %d functions\n", len(metadata.Functions))
}
Output: Query Analysis: - Joins 2 tables - References 8 columns - Uses 3 functions
Example (Batch) ¶
Example_batch demonstrates parsing multiple SQL statements efficiently.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
queries := []string{
"SELECT * FROM users",
"SELECT * FROM orders",
"SELECT * FROM products",
}
asts, err := gosqlx.ParseMultiple(queries)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Successfully parsed %d queries\n", len(asts))
}
Output: Successfully parsed 3 queries
Example (BatchValidation) ¶
Example_batchValidation demonstrates validating multiple queries.
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
queries := []string{
"SELECT * FROM users",
"INSERT INTO logs (message) VALUES ('test')",
"UPDATE users SET active = false WHERE id = 1",
"DELETE FROM temp_data WHERE created_at < NOW()",
}
if err := gosqlx.ValidateMultiple(queries); err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
fmt.Printf("All %d queries are valid\n", len(queries))
}
Output: All 4 queries are valid
Example (ComplexQuery) ¶
Example_complexQuery demonstrates parsing a complex SQL query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := `
SELECT
u.id,
u.name,
COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.active = true
GROUP BY u.id, u.name
ORDER BY order_count DESC
`
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed complex query with %d statement(s)\n", len(ast.Statements))
}
Output: Parsed complex query with 1 statement(s)
Example (Cte) ¶
Example_cte demonstrates parsing Common Table Expressions (CTEs).
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := `
WITH active_users AS (
SELECT * FROM users WHERE active = true
)
SELECT * FROM active_users
`
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Successfully parsed CTE query\n")
_ = ast
}
Output: Successfully parsed CTE query
Example (ErrorHandling) ¶
Example_errorHandling demonstrates proper error handling.
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM" // Invalid: missing table name
ast, err := gosqlx.Parse(sql)
if err != nil {
fmt.Println("Parse error occurred")
// In real code: log detailed error message
_ = err
return
}
_ = ast
}
Output: Parse error occurred
Example (ExtractColumns) ¶
Example_extractColumns demonstrates extracting column names from a query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT u.name, u.email FROM users u WHERE u.active = true ORDER BY u.created_at"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
columns := gosqlx.ExtractColumns(ast)
fmt.Printf("Found %d columns\n", len(columns))
}
Output: Found 4 columns
Example (ExtractFromCTE) ¶
Example_extractFromCTE demonstrates extracting from queries with CTEs.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := `WITH active_users AS (
SELECT id, name FROM users WHERE active = true
)
SELECT name, COUNT(*) FROM active_users GROUP BY name`
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
metadata := gosqlx.ExtractMetadata(ast)
fmt.Printf("Tables found: %d\n", len(metadata.Tables))
}
Output: Tables found: 2
Example (ExtractFunctions) ¶
Example_extractFunctions demonstrates extracting function names from a query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT COUNT(*), AVG(salary), UPPER(name) FROM employees"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
functions := gosqlx.ExtractFunctions(ast)
fmt.Printf("Found %d functions\n", len(functions))
}
Output: Found 3 functions
Example (ExtractMetadata) ¶
Example_extractMetadata demonstrates extracting comprehensive metadata from a query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := `SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.active = true
GROUP BY u.name
HAVING COUNT(o.id) > 5`
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
metadata := gosqlx.ExtractMetadata(ast)
fmt.Printf("Tables: %d, Columns: %d, Functions: %d\n",
len(metadata.Tables), len(metadata.Columns), len(metadata.Functions))
}
Output: Tables: 2, Columns: 4, Functions: 1
Example (ExtractTables) ¶
Example_extractTables demonstrates extracting table names from a query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users u JOIN orders o ON u.id = o.user_id"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
tables := gosqlx.ExtractTables(ast)
fmt.Printf("Found %d tables\n", len(tables))
}
Output: Found 2 tables
Example (ExtractTablesQualified) ¶
Example_extractTablesQualified demonstrates extracting qualified table names.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users JOIN orders ON users.id = orders.user_id"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
tables := gosqlx.ExtractTablesQualified(ast)
fmt.Printf("Found %d tables\n", len(tables))
}
Output: Found 2 tables
Example (ExtractWindowFunctions) ¶
Example_extractWindowFunctions demonstrates extracting window functions.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := `SELECT
name,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rank,
AVG(salary) OVER (PARTITION BY department) as dept_avg
FROM employees`
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
functions := gosqlx.ExtractFunctions(ast)
fmt.Printf("Window functions found: %d\n", len(functions))
}
Output: Window functions found: 2
Example (Format) ¶
Example_format demonstrates SQL formatting with options.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users WHERE active = true"
// Use default formatting options
opts := gosqlx.DefaultFormatOptions()
opts.AddSemicolon = true
formatted, err := gosqlx.Format(sql, opts)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Formatted SQL length: %d\n", len(formatted))
}
Output: Formatted SQL length: 40
Example (FormatWithOptions) ¶
Example_formatWithOptions demonstrates custom formatting options.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT id, name FROM users"
opts := gosqlx.FormatOptions{
IndentSize: 4,
UppercaseKeywords: true,
AddSemicolon: true,
SingleLineLimit: 80,
}
formatted, err := gosqlx.Format(sql, opts)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Formatted with custom options: %d chars\n", len(formatted))
}
Output: Formatted with custom options: 27 chars
Example (MigrationFromLowLevel) ¶
Example_migrationFromLowLevel demonstrates migrating from low-level API.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
// Instead of manually managing tokenizer and parser:
// tkz := tokenizer.GetTokenizer()
// defer tokenizer.PutTokenizer(tkz)
// tokens, err := tkz.Tokenize([]byte(sql))
// ...
// p := parser.NewParser()
// defer p.Release()
// ast, err := p.Parse(tokens)
// Simply use:
ast, err := gosqlx.Parse("SELECT * FROM users")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Migrated to simple API: %d statement(s)\n", len(ast.Statements))
}
Output: Migrated to simple API: 1 statement(s)
Example (MustParse) ¶
Example_mustParse demonstrates MustParse for SQL literals.
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
// Use MustParse only with SQL literals you control
// (e.g., in tests or initialization code)
ast := gosqlx.MustParse("SELECT 1")
fmt.Printf("Type: %T\n", ast)
}
Output: Type: *ast.AST
Example (ParseBytes) ¶
Example_parseBytes demonstrates parsing from a byte slice.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
// Useful when SQL is already in byte form (e.g., from file I/O)
sqlBytes := []byte("SELECT * FROM users")
ast, err := gosqlx.ParseBytes(sqlBytes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed from bytes: %d statement(s)\n", len(ast.Statements))
}
Output: Parsed from bytes: 1 statement(s)
Example (RealWorldUsage) ¶
Example_realWorldUsage demonstrates a realistic use case.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
// Validate user input before executing
userSQL := "SELECT * FROM users WHERE id = 1"
// First validate
if err := gosqlx.Validate(userSQL); err != nil {
fmt.Println("Invalid SQL from user")
return
}
// Parse to inspect structure
ast, err := gosqlx.Parse(userSQL)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Valid query with %d statement(s)\n", len(ast.Statements))
}
Output: Valid query with 1 statement(s)
Example (Simple) ¶
Example_simple demonstrates the simplest way to parse SQL.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed %d statement(s)\n", len(ast.Statements))
}
Output: Parsed 1 statement(s)
Example (Validate) ¶
Example_validate demonstrates SQL validation.
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
// Valid SQL
if err := gosqlx.Validate("SELECT * FROM users"); err != nil {
fmt.Println("Invalid SQL")
} else {
fmt.Println("Valid SQL")
}
// Invalid SQL
if err := gosqlx.Validate("INVALID SQL"); err != nil {
fmt.Println("Invalid SQL detected")
}
}
Output: Valid SQL Invalid SQL detected
Example (ValidateMultiple) ¶
Example_validateMultiple demonstrates validating multiple SQL statements.
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
queries := []string{
"SELECT * FROM users",
"INSERT INTO users (name) VALUES ('test')",
"UPDATE users SET active = true WHERE id = 1",
}
if err := gosqlx.ValidateMultiple(queries); err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
fmt.Println("All queries are valid")
}
Output: All queries are valid
Example (ValidationWithExtraction) ¶
Example_validationWithExtraction demonstrates combining validation with metadata extraction.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
userSQL := "SELECT u.id, u.name FROM users u WHERE u.status = 'active'"
// First validate
if err := gosqlx.Validate(userSQL); err != nil {
fmt.Println("Invalid SQL")
return
}
// Parse and extract metadata
ast, err := gosqlx.Parse(userSQL)
if err != nil {
log.Fatal(err)
}
metadata := gosqlx.ExtractMetadata(ast)
// Check if accessing sensitive tables
sensitiveTable := "users"
for _, table := range metadata.Tables {
if table == sensitiveTable {
fmt.Printf("Query accesses sensitive table: %s\n", sensitiveTable)
}
}
}
Output: Query accesses sensitive table: users
Example (WindowFunctions) ¶
Example_windowFunctions demonstrates parsing SQL with window functions.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT name, salary, ROW_NUMBER() OVER (ORDER BY salary DESC) as rank FROM employees"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Successfully parsed window function query\n")
_ = ast
}
Output: Successfully parsed window function query
Index ¶
- func ExtractColumns(astNode *ast.AST) []string
- func ExtractFunctions(astNode *ast.AST) []string
- func ExtractTables(astNode *ast.AST) []string
- func Format(sql string, options FormatOptions) (string, error)
- func MustParse(sql string) *ast.AST
- func Parse(sql string) (*ast.AST, error)
- func ParseBytes(sql []byte) (*ast.AST, error)
- func ParseMultiple(queries []string) ([]*ast.AST, error)
- func ParseWithContext(ctx context.Context, sql string) (*ast.AST, error)
- func ParseWithTimeout(sql string, timeout time.Duration) (*ast.AST, error)
- func Validate(sql string) error
- func ValidateMultiple(queries []string) error
- type FormatOptions
- type Metadata
- type QualifiedName
Examples ¶
- Package (AdvancedFeatures)
- Package (AnalyzeQuery)
- Package (Batch)
- Package (BatchValidation)
- Package (ComplexQuery)
- Package (Cte)
- Package (ErrorHandling)
- Package (ExtractColumns)
- Package (ExtractFromCTE)
- Package (ExtractFunctions)
- Package (ExtractMetadata)
- Package (ExtractTables)
- Package (ExtractTablesQualified)
- Package (ExtractWindowFunctions)
- Package (Format)
- Package (FormatWithOptions)
- Package (MigrationFromLowLevel)
- Package (MustParse)
- Package (ParseBytes)
- Package (RealWorldUsage)
- Package (Simple)
- Package (Validate)
- Package (ValidateMultiple)
- Package (ValidationWithExtraction)
- Package (WindowFunctions)
- ExtractColumns
- ExtractColumnsQualified
- ExtractFunctions
- ExtractMetadata
- ExtractTables
- ExtractTablesQualified
- Format
- Format
- MustParse
- Parse
- Parse
- ParseBytes
- ParseMultiple
- ParseMultiple
- ParseWithContext
- ParseWithTimeout
- Validate
- Validate
- ValidateMultiple
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExtractColumns ¶ added in v1.6.0
ExtractColumns extracts all column references from an AST.
This function traverses the AST and collects column references from:
- SELECT lists
- WHERE conditions
- GROUP BY clauses
- ORDER BY clauses
- JOIN conditions
- HAVING clauses
Returns a deduplicated slice of column names (without table qualifiers).
Example:
sql := "SELECT u.name, u.email FROM users u WHERE u.active = true ORDER BY u.created_at" ast, _ := gosqlx.Parse(sql) columns := gosqlx.ExtractColumns(ast) // columns = ["name", "email", "active", "created_at"]
Example ¶
ExampleExtractColumns demonstrates extracting column names from a query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT u.name, u.email FROM users u WHERE u.active = true ORDER BY u.created_at"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
columns := gosqlx.ExtractColumns(ast)
fmt.Printf("Found %d columns\n", len(columns))
}
Output: Found 4 columns
func ExtractFunctions ¶ added in v1.6.0
ExtractFunctions extracts all function calls from an AST.
This function traverses the AST and collects all function names, including:
- Aggregate functions (COUNT, SUM, AVG, etc.)
- Window functions (ROW_NUMBER, RANK, etc.)
- Scalar functions (UPPER, LOWER, NOW, etc.)
Returns a deduplicated slice of function names.
Example:
sql := "SELECT COUNT(*), UPPER(name) FROM users" ast, _ := gosqlx.Parse(sql) functions := gosqlx.ExtractFunctions(ast) // functions = ["COUNT", "UPPER"]
Example ¶
ExampleExtractFunctions demonstrates extracting function names from a query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT COUNT(*), AVG(salary), UPPER(name) FROM employees"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
functions := gosqlx.ExtractFunctions(ast)
fmt.Printf("Found %d functions\n", len(functions))
}
Output: Found 3 functions
func ExtractTables ¶ added in v1.6.0
ExtractTables extracts all table names from an AST.
This function traverses the AST and collects all table references from:
- FROM clauses
- JOIN clauses
- Subqueries and CTEs
- INSERT/UPDATE/DELETE statements
Returns a deduplicated slice of table names.
Example:
sql := "SELECT * FROM users u JOIN orders o ON u.id = o.user_id" ast, _ := gosqlx.Parse(sql) tables := gosqlx.ExtractTables(ast) // tables = ["users", "orders"]
Example ¶
ExampleExtractTables demonstrates extracting table names from a query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users u JOIN orders o ON u.id = o.user_id"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
tables := gosqlx.ExtractTables(ast)
fmt.Printf("Found %d tables\n", len(tables))
}
Output: Found 2 tables
func Format ¶
func Format(sql string, options FormatOptions) (string, error)
Format formats SQL according to the specified options.
This is a placeholder implementation that currently validates the SQL and returns it with basic formatting. Full AST-based formatting will be implemented in a future version.
Example:
sql := "select * from users where active=true" opts := gosqlx.DefaultFormatOptions() opts.UppercaseKeywords = true formatted, err := gosqlx.Format(sql, opts)
Returns the formatted SQL string or an error if SQL is invalid.
Example ¶
Example demonstrating SQL formatting
sql := "SELECT * FROM users WHERE active = true"
opts := DefaultFormatOptions()
opts.AddSemicolon = true
formatted, err := Format(sql, opts)
if err != nil {
panic(err)
}
_ = formatted
Example ¶
ExampleFormat demonstrates SQL formatting with options.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users WHERE active = true"
opts := gosqlx.DefaultFormatOptions()
opts.AddSemicolon = true
formatted, err := gosqlx.Format(sql, opts)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Formatted SQL ends with semicolon: %v\n", formatted[len(formatted)-1] == ';')
}
Output: Formatted SQL ends with semicolon: true
func MustParse ¶
MustParse is like Parse but panics on error.
This is useful for parsing SQL literals at startup or in tests where parse errors indicate a programming bug.
Example:
// In test or init()
ast := gosqlx.MustParse("SELECT 1")
Example ¶
ExampleMustParse demonstrates MustParse for SQL literals.
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
// Use MustParse only with SQL literals you control
ast := gosqlx.MustParse("SELECT 1")
fmt.Printf("Type: %T\n", ast)
}
Output: Type: *ast.AST
func Parse ¶
Parse is a convenience function that tokenizes and parses SQL in one call.
This function handles all object pool management internally, making it ideal for simple use cases where performance overhead is acceptable.
Example:
sql := "SELECT * FROM users WHERE active = true"
astNode, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed: %T\n", astNode)
For batch processing or performance-critical code, use the lower-level tokenizer and parser APIs directly to reuse objects.
Example ¶
ExampleParse demonstrates basic SQL parsing.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users WHERE active = true"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed %d statement(s)\n", len(ast.Statements))
}
Output: Parsed 1 statement(s)
Example ¶
Example demonstrating the simple Parse API
sql := "SELECT * FROM users WHERE active = true"
ast, err := Parse(sql)
if err != nil {
panic(err)
}
// Use the AST
_ = ast
func ParseBytes ¶
ParseBytes is like Parse but accepts a byte slice.
This is useful when you already have SQL as bytes (e.g., from file I/O) and want to avoid the string → []byte conversion overhead.
Example:
sqlBytes := []byte("SELECT * FROM users")
astNode, err := gosqlx.ParseBytes(sqlBytes)
Example ¶
ExampleParseBytes demonstrates parsing from a byte slice.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sqlBytes := []byte("SELECT * FROM users")
ast, err := gosqlx.ParseBytes(sqlBytes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed from bytes: %d statement(s)\n", len(ast.Statements))
}
Output: Parsed from bytes: 1 statement(s)
func ParseMultiple ¶
ParseMultiple parses multiple SQL statements and returns their ASTs.
This is more efficient than calling Parse() repeatedly because it reuses the tokenizer and parser objects.
Example:
queries := []string{
"SELECT * FROM users",
"SELECT * FROM orders",
}
asts, err := gosqlx.ParseMultiple(queries)
Example ¶
Example demonstrating batch parsing
queries := []string{
"SELECT * FROM users",
"SELECT * FROM orders",
}
asts, err := ParseMultiple(queries)
if err != nil {
panic(err)
}
for i, ast := range asts {
_ = i
_ = ast
}
Example ¶
ExampleParseMultiple demonstrates parsing multiple SQL statements efficiently.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
queries := []string{
"SELECT * FROM users",
"SELECT * FROM orders",
"SELECT * FROM products",
}
asts, err := gosqlx.ParseMultiple(queries)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed %d queries\n", len(asts))
}
Output: Parsed 3 queries
func ParseWithContext ¶
ParseWithContext is a convenience function that tokenizes and parses SQL with context support.
This function handles all object pool management internally and supports cancellation via the provided context. It's ideal for long-running operations that need to be cancellable or have timeouts.
Returns context.Canceled if the context is cancelled during parsing, or context.DeadlineExceeded if the timeout expires.
Example:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
astNode, err := gosqlx.ParseWithContext(ctx, sql)
if err == context.DeadlineExceeded {
log.Println("Parsing timed out")
}
Example ¶
ExampleParseWithContext demonstrates parsing with context for cancellation.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
sql := "SELECT * FROM users"
ast, err := gosqlx.ParseWithContext(ctx, sql)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed with context: %d statement(s)\n", len(ast.Statements))
}
Output: Parsed with context: 1 statement(s)
func ParseWithTimeout ¶
ParseWithTimeout is a convenience function that parses SQL with a timeout.
This is a wrapper around ParseWithContext that creates a timeout context automatically. It's useful for quick timeout-based parsing without manual context management.
Example:
astNode, err := gosqlx.ParseWithTimeout(sql, 5*time.Second)
if err == context.DeadlineExceeded {
log.Println("Parsing timed out after 5 seconds")
}
Example ¶
ExampleParseWithTimeout demonstrates parsing with a timeout.
package main
import (
"fmt"
"log"
"time"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users"
ast, err := gosqlx.ParseWithTimeout(sql, 5*time.Second)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed with timeout: %d statement(s)\n", len(ast.Statements))
}
Output: Parsed with timeout: 1 statement(s)
func Validate ¶
Validate checks if the given SQL is syntactically valid.
This is a convenience function that only validates syntax without building the full AST, making it slightly faster than Parse().
Example:
if err := gosqlx.Validate("SELECT * FROM users"); err != nil {
fmt.Printf("Invalid SQL: %v\n", err)
}
Returns nil if SQL is valid, or an error describing the problem.
Example ¶
ExampleValidate demonstrates SQL validation.
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users"
if err := gosqlx.Validate(sql); err != nil {
fmt.Printf("Invalid SQL: %v\n", err)
return
}
fmt.Println("Valid SQL")
}
Output: Valid SQL
Example ¶
Example demonstrating SQL validation
if err := Validate("SELECT * FROM users"); err != nil {
panic(err)
}
func ValidateMultiple ¶
ValidateMultiple validates multiple SQL statements.
Returns nil if all statements are valid, or an error for the first invalid statement encountered.
Example:
queries := []string{
"SELECT * FROM users",
"INVALID SQL HERE",
}
if err := gosqlx.ValidateMultiple(queries); err != nil {
fmt.Printf("Validation failed: %v\n", err)
}
Example ¶
ExampleValidateMultiple demonstrates validating multiple SQL statements.
package main
import (
"fmt"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
queries := []string{
"SELECT * FROM users",
"INSERT INTO users (name) VALUES ('test')",
"UPDATE users SET active = true WHERE id = 1",
}
if err := gosqlx.ValidateMultiple(queries); err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
fmt.Println("All queries valid")
}
Output: All queries valid
Types ¶
type FormatOptions ¶
type FormatOptions struct {
// IndentSize is the number of spaces to use for indentation (default: 2)
IndentSize int
// Uppercase keywords (default: false)
UppercaseKeywords bool
// AddSemicolon adds a semicolon at the end if missing (default: false)
AddSemicolon bool
// SingleLineLimit is the maximum line length before breaking (default: 80)
// Note: Currently a placeholder for future implementation
SingleLineLimit int
}
FormatOptions controls SQL formatting behavior.
func DefaultFormatOptions ¶
func DefaultFormatOptions() FormatOptions
DefaultFormatOptions returns the default formatting options.
type Metadata ¶ added in v1.6.0
type Metadata struct {
Tables []string // Simple table names
TablesQualified []QualifiedName // Qualified table names
Columns []string // Column names
ColumnsQualified []QualifiedName // Qualified column names
Functions []string // Function names
}
Metadata contains all extracted metadata from a SQL query.
func ExtractMetadata ¶ added in v1.6.0
ExtractMetadata extracts comprehensive metadata from an AST.
This is a convenience function that calls all extraction functions and returns the results in a structured format.
Example:
sql := "SELECT COUNT(*), u.name FROM users u WHERE u.active = true"
ast, _ := gosqlx.Parse(sql)
metadata := gosqlx.ExtractMetadata(ast)
fmt.Printf("Tables: %v, Columns: %v, Functions: %v\n",
metadata.Tables, metadata.Columns, metadata.Functions)
Example ¶
ExampleExtractMetadata demonstrates extracting comprehensive metadata from a query.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := `SELECT u.name, COUNT(o.id) as order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.active = true
GROUP BY u.name
HAVING COUNT(o.id) > 5`
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
metadata := gosqlx.ExtractMetadata(ast)
fmt.Printf("Tables: %d, Columns: %d, Functions: %d\n",
len(metadata.Tables), len(metadata.Columns), len(metadata.Functions))
}
Output: Tables: 2, Columns: 4, Functions: 1
type QualifiedName ¶ added in v1.6.0
type QualifiedName struct {
Schema string // Optional schema name
Table string // Table name (or middle qualifier)
Name string // Column or table name
}
QualifiedName represents a fully qualified table or column name. It can represent schema.table, table.column, or schema.table.column.
func ExtractColumnsQualified ¶ added in v1.6.0
func ExtractColumnsQualified(astNode *ast.AST) []QualifiedName
ExtractColumnsQualified extracts all column references with their table qualifiers.
This function is similar to ExtractColumns but preserves table qualifier information when present in the original query. It collects column references from:
- SELECT lists
- WHERE conditions
- GROUP BY clauses
- ORDER BY clauses
- JOIN conditions
- HAVING clauses
Returns a deduplicated slice of QualifiedName objects representing columns.
Example:
sql := "SELECT u.name, u.email FROM users u WHERE u.active = true"
ast, _ := gosqlx.Parse(sql)
columns := gosqlx.ExtractColumnsQualified(ast)
// columns contains QualifiedName{Table: "u", Name: "name"},
// QualifiedName{Table: "u", Name: "email"}, QualifiedName{Table: "u", Name: "active"}
Example ¶
ExampleExtractColumnsQualified demonstrates extracting qualified column names.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT u.name, u.email FROM users u WHERE u.active = true"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
columns := gosqlx.ExtractColumnsQualified(ast)
fmt.Printf("Found %d qualified columns\n", len(columns))
}
Output: Found 3 qualified columns
func ExtractTablesQualified ¶ added in v1.6.0
func ExtractTablesQualified(astNode *ast.AST) []QualifiedName
ExtractTablesQualified extracts all table names with their qualifiers (schema.table).
This function is similar to ExtractTables but preserves schema information when present in the original query.
Returns a deduplicated slice of QualifiedName objects.
Example:
sql := "SELECT * FROM public.users JOIN app.orders ON users.id = orders.user_id"
ast, _ := gosqlx.Parse(sql)
tables := gosqlx.ExtractTablesQualified(ast)
// tables contains QualifiedName{Schema: "public", Name: "users"} and
// QualifiedName{Schema: "app", Name: "orders"}
Example ¶
ExampleExtractTablesQualified demonstrates extracting qualified table names.
package main
import (
"fmt"
"log"
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
)
func main() {
sql := "SELECT * FROM users JOIN orders ON users.id = orders.user_id"
ast, err := gosqlx.Parse(sql)
if err != nil {
log.Fatal(err)
}
tables := gosqlx.ExtractTablesQualified(ast)
fmt.Printf("Found %d tables\n", len(tables))
}
Output: Found 2 tables
func (QualifiedName) FullName ¶ added in v1.6.0
func (q QualifiedName) FullName() string
FullName returns the full name without schema qualifier. This method strips the schema component and returns the meaningful identifier.
Behavior:
- For 3-part names (schema.table.column): Returns table.column (drops schema)
- For 2-part names (table.column OR schema.table): Returns table.column
- For single-part names: Returns the name
Examples:
- QualifiedName{Schema: "db", Table: "public", Name: "users"} → "public.users"
- QualifiedName{Table: "users", Name: "id"} → "users.id"
- QualifiedName{Name: "id"} → "id"
- QualifiedName{Schema: "public", Name: "users"} → "users"
- QualifiedName{Table: "users"} → "users"
func (QualifiedName) String ¶ added in v1.6.0
func (q QualifiedName) String() string
String returns the qualified name as a string.