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.Nodeinstance 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 anNodeinstance.Accessing an instance with a positive index returns the nth node up in the hierarchy.
When applied (using the
@operator) to anast.Nodeinstance 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 thefunctionsslot ofRangeFunctionthat is a tuple of tuples, each containing aFuncCalland 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_XYZwhereXYZis the name of a class name defined in thepglast.astmodule.Instances of this class are callables and accept either a
ast.Nodeinstance or a sequence of instances, typically the result ofparse_sql. The argument will be traversed in a breadth first order and eachNodeinstance will be passed to the correspondingvisit_XYZmethod if it is implemented, falling back to the defaultvisitmethod. If none of them are defined, the node will be ignored.The
visit_XYZmethods receive two arguments: the ancestry chain of the node, an instance ofAncestorand theNodeinstance 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.Nodeinstance or a tuple of those
This is a generator, that yields
Nodeinstances 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
SQLstatement or aast.Nodeinstance- 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'}