pglast.visitors
— Other ways to inspect and manipulate the AST¶
- class pglast.visitors.Action¶
Abstract action singleton.
- class pglast.visitors.ActionMeta¶
Metaclass used to implement action singleton.
- class pglast.visitors.Add¶
Marker used to tell the iterator to insert nodes in the current sequence.
- class pglast.visitors.Ancestor(parent=None, node=None, member=None)¶
Simple object to keep track of the node’s ancestors while it’s being visited.
- Parameters:
parent (Ancestor) – the parent of the new instance
node – the tracked object
member – either the name of the attribute or the index in the sequence that points to the tracked object in the parent container
An instance of this class represent a particular ancestor in the hierarchy chain: it carries a reference that points to the higher item in the chain, the associated
ast.Node
instance and a member, either the attribute name or sequential index in the parent node: the latter happens when the parent node is actually a tuple, not anNode
instance.Accessing an instance with a positive index returns the nth node up in the hierarchy.
When applied (using the
@
operator) to anast.Node
instance will traverse that node returning the leaf one corresponding to the whole chain.Example:
>>> tree = parse_sql('select 1') >>> root = Ancestor() >>> root ROOT >>> root@tree is tree True >>> root[0] is None True >>> select_stmt_path = root / (tree, 0) / (tree[0], 'stmt') >>> select_stmt_path ROOT → 0 → stmt >>> select_stmt_path@tree is tree[0].stmt True >>> select_stmt_path[0] is tree[0] True >>> columns_path = (select_stmt_path ... / (tree[0].stmt, 'targetList')) >>> first_col_path = (columns_path ... / (tree[0].stmt.targetList[0], 0)) >>> first_col_path ROOT → 0 → stmt → targetList → 0 >>> first_col_path[0] <ResTarget val=<A_Const isnull=False val=<Integer ival=1>>> >>> first_col_path[1] is columns_path[0] True
As said, the node is not always a
ast.Node
, but may be a tuple, possibly containing subtuples, for example thefunctions
slot ofRangeFunction
that is a tuple of tuples, each containing aFuncCall
and possibly other values:>>> tree = parse_sql('SELECT * FROM ROWS' ... ' FROM (generate_series(10,11),' ... ' get_users())') >>> class VerboseVisitor(Visitor): ... all_ancestors = [] ... def visit(self, ancestors, node): ... print(f'{len(self.all_ancestors):2d}.', ... "node:", type(node).__name__, ... "ancestor:", type(ancestors.node).__name__) ... self.all_ancestors.append(ancestors) >>> VerboseVisitor()(tree) 0. node: RawStmt ancestor: tuple 1. node: SelectStmt ancestor: RawStmt 2. node: ResTarget ancestor: tuple 3. node: RangeFunction ancestor: tuple 4. node: ColumnRef ancestor: ResTarget 5. node: A_Star ancestor: tuple 6. node: FuncCall ancestor: tuple 7. node: FuncCall ancestor: tuple 8. node: String ancestor: tuple 9. node: A_Const ancestor: tuple 10. node: A_Const ancestor: tuple 11. node: String ancestor: tuple 12. node: Integer ancestor: A_Const 13. node: Integer ancestor: A_Const ...
To find the closest ancestor that is actually pointing to an AST node you may use the
abs()
function:>>> range_function = tree[0].stmt.fromClause[0] >>> gen_series_funccall = range_function.functions[0][0] >>> gen_series_funccall <FuncCall funcname=(<String sval='generate_series'>,) ...> >>> generate_series_ancestry = VerboseVisitor.all_ancestors[6] >>> generate_series_ancestry@tree is gen_series_funccall True >>> abs(generate_series_ancestry).node is range_function True
As an aid to visitors that apply changes to the AST, there are two methods,
update()
andapply()
, that takes care of the different cases, when node is an AST instance or instead it’s a tuple (or subtuple); the former does not directly change the AST tree, but postpones that when the latter is called.- apply()¶
Apply the pending change, if any, to the actual node.
- find_nearest(cls)¶
Find the nearest ancestor with a node of the given cls.
- update(new_value)¶
Set new_value as a pending change to the tracked node.
- class pglast.visitors.Continue¶
Marker used to tell the iterator to keep going.
- class pglast.visitors.Delete¶
Marker used to tell the iterator to delete current node.
- class pglast.visitors.ReferencedRelations(cte_names=None, skip_with_clause=None)¶
Concrete implementation of the
referenced_relations()
function.- Parameters:
cte_names (set) – the set of surrounding CTE names
skip_with_clause (WithClause) – skip this clause, when specified
Calling an instance of this class will return a set of the names of the relations referenced by the given
node
.- visit_RangeVar(ancestors, node)¶
Collect relation names, taking into account defined CTE names
- class pglast.visitors.Skip¶
Marker used to tell the iterator to not descend into the current node.
- class pglast.visitors.Visitor¶
Base class implementing the visitor pattern.
To use it, you shall write a subclass that implements a set of particular named methods, specifically
visit_XYZ
whereXYZ
is the name of a class name defined in thepglast.ast
module.Instances of this class are callables and accept either a
ast.Node
instance or a sequence of instances, typically the result ofparse_sql
. The argument will be traversed in a breadth first order and eachNode
instance will be passed to the correspondingvisit_XYZ
method if it is implemented, falling back to the defaultvisit
method. If none of them are defined, the node will be ignored.The
visit_XYZ
methods receive two arguments: the ancestry chain of the node, an instance ofAncestor
and theNode
instance itself. The methods may return eitherNone
, an action or a new node that will replace the original one.- iterate(node)¶
Iterate thru node’s AST using a breadth-first traversing.
- Parameters:
node – either a
ast.Node
instance or a tuple of those
This is a generator, that yields
Node
instances together with their ancestors chain as it finds them while traversing the tree.
- visit = None¶
The default visit method for any node without a specific one. When
None
, nothing happens.
- pglast.visitors.referenced_relations(stmt)¶
Return the set of relation names referenced in the given stmt.
- Parameters:
stmt – either a string containing the
SQL
statement or aast.Node
instance- Returns:
a set of strings, the names of the relations
Example:
>>> referenced_relations('WITH q1(x,y) AS (SELECT 1,2)' ... ' SELECT * FROM q1, q2') {'q2'}