Overview
Thewalker package provides utilities for traversing PostgreSQL abstract syntax trees (AST). It enables you to visit every node in a parse tree to find specific patterns, collect information, or analyze SQL structure.
Visitor Function Type
TheVisitor function type is called for each node during AST traversal.
The current AST node being visited
bool - Return true to continue traversing child nodes, false to stop traversal
Example:
Functions
Walk
Recursively visits every node in the parse tree rooted at the given node.The root node to start traversal from
The visitor function called for each node
- Calls
visitfor the current node - If
visitreturnstrue, recursively walks all child nodes - If
visitreturnsfalse, stops traversal immediately - Safely handles
nilnodes
Children
Returns the direct child nodes of a given node.The parent node to extract children from
[]*pg_query.Node - Slice of direct child nodes (may be empty)
Behavior:
- Returns only immediate children, not descendants
- Safely handles
nilnodes (returnsnil) - Filters out
nilchildren automatically - Different node types have different child structures
Supported Node Types
TheChildren function supports extracting child nodes from these statement types:
DML Statements
SELECT queries including:
- DistinctClause, TargetList (select items)
- FromClause (tables/joins)
- WhereClause, HavingClause
- GroupClause, WindowClause
- SortClause (ORDER BY)
- LimitOffset, LimitCount
- LockingClause (FOR UPDATE)
- WithClause (CTEs)
- Larg, Rarg (UNION/INTERSECT operands)
INSERT statements including:
- Relation (target table)
- Cols (column list)
- SelectStmt (VALUES or SELECT)
- ReturningList
- WithClause (CTEs)
UPDATE statements including:
- Relation (target table)
- TargetList (SET clauses)
- WhereClause
- FromClause
- ReturningList
- WithClause (CTEs)
DELETE statements including:
- Relation (target table)
- UsingClause
- WhereClause
- ReturningList
- WithClause (CTEs)
Expression Nodes
Table joins including:
- Larg, Rarg (left/right operands)
- Quals (ON condition)
- UsingClause
Boolean expressions (AND, OR, NOT):
- Args (operands)
Binary expressions (=, <, >, LIKE, etc.):
- Lexpr, Rexpr (left/right operands)
- Name (operator name)
Function calls including:
- Funcname (function name parts)
- Args (function arguments)
- AggOrder (ORDER BY in aggregates)
- AggFilter (FILTER clause)
CASE expressions:
- Arg (case operand)
- Args (WHEN clauses)
- Defresult (ELSE clause)
CASE WHEN clauses:
- Expr (condition)
- Result (result value)
Subqueries (IN, EXISTS, etc.):
- Testexpr (left side of comparison)
- Subselect (subquery)
COALESCE expressions:
- Args (arguments)
IS NULL / IS NOT NULL:
- Arg (tested expression)
Other Nodes
CTEs (WITH clauses):
- Ctequery (CTE query)
- Aliascolnames (column aliases)
Subqueries in FROM:
- Subquery (the SELECT)
SELECT list items / SET targets:
- Val (value expression)
- Indirection (array subscripts, field access)
Column references:
- Fields (schema.table.column parts)
Type casts (::type):
- Arg (casted expression)
ORDER BY items:
- Node (sorted expression)
- UseOp (custom sort operator)
Generic node lists:
- Items (list elements)
ROW constructors:
- Args (row values)
GREATEST/LEAST:
- Args (arguments)
XML functions:
- NamedArgs, Args
GROUPING function:
- Args (arguments)
FOR UPDATE/SHARE:
- LockedRels (locked tables)
Complete Example: Find Unindexed LIKE Patterns
Here’s a realistic example that finds LIKE patterns starting with wildcards (which can’t use indexes):Best Practices
- Return early: Return
falsefrom visitor when you’ve found what you need - Check for nil: Always check if node getters return
nilbefore accessing fields - Use Walk for deep search: Use
Walkwhen you need to search the entire tree - Use Children for direct access: Use
Childrenwhen you only need immediate children - Combine with type assertions: Use node getter methods to access specific node types
See Also
- Rule Interface - Implement custom rules
- Analyzer - Run rules against SQL files
- pg_query_go - PostgreSQL parser library