On this page
Package sqlexpr is a recursive-descent parser for a subset of PostgreSQL expressions, producing an AST for analysis, validation, and code generation.
#internal/sqlexpr
#internal/sqlexpr
Package sqlexpr is a recursive descent parser for a subset of PostgreSQL SQL expressions. It tokenizes an input string and produces an AST of Node values suitable for static analysis, validation, and code generation.
Operator precedence
Levels from lowest to highest binding:
1. OR 2. AND 3. NOT (unary prefix) 4. Comparison: =, !=, <>, <, >, <=, >=, ~, ~, !~, !~, IS NULL, IS NOT NULL, IS DISTINCT FROM, IN, NOT IN, BETWEEN, LIKE, ILIKE, NOT LIKE, NOT ILIKE 5. Concatenation: || 6. Addition/Subtraction: +, - 7. Multiplication/Division/Modulo: *, /, % 8. Cast: :: 9. Primary: literals, identifiers, function calls, parenthesized expressions, unary minus, EXISTS, CASE
Node types
The AST consists of the following node types, all implementing [Node]:
- [ColumnRef]: column reference, optionally qualified (column, table.column, schema.table.column) - [BoolLiteral]: true or false - [StringLiteral]: single-quoted string - [IntLiteral]: integer - [FloatLiteral]: floating-point number - [NullLiteral]: NULL - [FuncCall]: function call with arguments - [Cast]: PostgreSQL :: cast operator - [BinaryOp]: binary operation (arithmetic, comparison, logical) - [UnaryOp]: unary operation (NOT, IS NULL, IS NOT NULL, unary minus) - [ExistsExpr]: EXISTS (subquery) - [SelectExpr]: simple SELECT inside EXISTS (columns, FROM, optional WHERE) - [ParenExpr]: parenthesized expression - [CaseExpr]: CASE WHEN ... THEN ... ELSE ... END (with [WhenClause])
Keywords
The following keywords are recognized (case-insensitive): OR, AND, NOT, IS, NULL, DISTINCT, FROM, IN, BETWEEN, LIKE, ILIKE, EXISTS, SELECT, WHERE, CASE, WHEN, THEN, ELSE, END, TRUE, FALSE, CAST, AS.
Limitations
- No full SELECT statements; only simple SELECT inside EXISTS with FROM and optional WHERE. - No window functions, CTEs (WITH), or aggregate DISTINCT (e.g., COUNT(DISTINCT x)). - No ORDER BY, GROUP BY, HAVING, or LIMIT. - No subqueries outside EXISTS. - No array subscript notation. - No SIMILAR TO, ANY, or ALL operators. - No type modifiers in casts (e.g., ::varchar(255)).
#Node
type Node interfaceNode is the interface all AST nodes implement.
#ColumnRef
type ColumnRef structColumnRef is a column reference, optionally qualified. Parts: ["column"], ["table", "column"], or ["schema", "table", "column"].
#BoolLiteral
type BoolLiteral structBoolLiteral is a boolean literal (true/false).
#StringLiteral
type StringLiteral structStringLiteral is a single-quoted string literal.
#IntLiteral
type IntLiteral structIntLiteral is an integer literal.
#FloatLiteral
type FloatLiteral structFloatLiteral is a floating-point literal.
#NullLiteral
type NullLiteral struct{}NullLiteral is a NULL literal.
#FuncCall
type FuncCall structFuncCall is a function call with arguments.
#Cast
type Cast structCast is a type cast expression (expr::type).
#BinaryOp
type BinaryOp structBinaryOp is a binary operation (left op right).
#UnaryOp
type UnaryOp structUnaryOp is a unary operation (e.g., NOT expr).
#ExistsExpr
type ExistsExpr structExistsExpr is an EXISTS (subquery) expression.
#SelectExpr
type SelectExpr structSelectExpr is a SELECT statement inside EXISTS.
#ParenExpr
type ParenExpr structParenExpr is a parenthesized expression.
#CaseExpr
type CaseExpr structCaseExpr is a CASE WHEN ... THEN ... [ELSE ...] END expression.
#WhenClause
type WhenClause structWhenClause is a WHEN condition THEN result pair.
#ParseError
type ParseError structParseError is a structured error with position information from the parser.
#Parse
func Parse(input string) (Node, error)Parse parses a SQL expression string into an AST. It handles arithmetic, comparisons, boolean logic, function calls, casts, CASE expressions, and EXISTS subqueries. See the package documentation for the full grammar.
On failure, the returned error is a *[ParseError] (which implements error). ParseError contains Pos (byte offset in the input string), Token (the problematic token text), and Msg (human-readable description) for precise error location reporting.
#Walk
func Walk(node Node, fn func(Node) bool)Walk traverses the AST in depth-first order, calling fn for each node. If fn returns false, children of that node are not visited.
#CollectColumnRefs
func CollectColumnRefs(node Node) []*ColumnRefCollectColumnRefs walks the AST and returns all ColumnRef nodes found.
#ParseError.Error
func (e *ParseError) Error() string