pglast.precedence — Operators precedence logic

The functions here answer the question “does this node need to be wrapped in parentheses when it is used as an operand of that other expression?”, which cannot be decided by looking at a node alone: the same node needs parens in one slot and not in another.

The vocabulary mirrors the PostgreSQL grammar rules: an expression is printed either in an a_expr, a b_expr or a c_expr context, and the rule that handles a node determines its precedence.

class pglast.precedence.ExprContext(*values)

Which grammar rule a value is being printed into.

This is internal vocabulary: it is never user visible.

class pglast.precedence.ExprPrec(*values)

The precedence of the expression, from the loosest to the tightest.

The value mirrors the order in which the corresponding rules appear in the PostgreSQL grammar, so that a node binding looser than another has a smaller value.

ADD = 7

+ -

AND = 1

AND

AT = 10

AT TIME ZONE, AT LOCAL

ATOM = 13

c_expr, typecasts, and anything else that cannot be split apart

BETWEEN = 5

BETWEEN IN LIKE ILIKE SIMILAR (non-associative)

COLLATE = 11

COLLATE

COMPARISON = 4

< > = <= >= <> (non-associative)

EXP = 9

^

IS = 3

IS, ISNULL, NOTNULL (non-associative)

MUL = 8

* / %

NOT = 2

NOT (right-associative)

OP = 6

Op/OPERATOR, i.e. all other operators

OR = 0

OR

UMINUS = 12

unary + - (right-associative)

class pglast.precedence.Side(*values)

The side of an operator an operand appears on.

pglast.precedence.expr_precedence(node, stream)

Return the precedence of the grammar rule that node is printed by.

Parameters:
  • node – an .ast.Node instance

  • stream – the stream that is printing the node

Returns:

ExprPrec

pglast.precedence.is_b_expr_rule(node, stream)

Whether node is handled by a b_expr rule, so it may appear in a b_expr context.

Parameters:
  • node – an .ast.Node instance

  • stream – the stream that is printing the node

Returns:

bool

Everything that is not handled by a b_expr rule (e.g. NOT, IS NULL, COLLATE, AT TIME ZONE) is only handled by the a_expr rule and needs explicit parens when used in a b_expr context.

pglast.precedence.is_subquery_comparison_form(node)

Whether node is a subquery comparison form: x = ANY (...), x < ALL (...).

Parameters:

node – an .ast.Node instance

Returns:

bool

x IN (...) and the like. As the left operand of an operator at the same precedence these never need parens (see needs_parens_for_precedence()); at any other precedence the normal rules apply, since dropping parens there can reassociate the expression or fail to parse: d = x = ANY(c) is rejected outright, and d || x = ANY(c) reparses with the comparison swallowing the concatenation.

pglast.precedence.needs_parens_as_c_expr(node, stream)

Whether node needs parens when used in a c_expr context.

Parameters:
  • node – an .ast.Node instance

  • stream – the stream that is printing the node

Returns:

bool

pglast.precedence.needs_parens_for_precedence(node, parent_prec, side, stream)

Whether node needs parens as the side operand of an expression with parent_prec.

Parameters:
  • node – an .ast.Node instance

  • parent_prec (ExprPrec) – the precedence of the enclosing expression

  • side (Side) – either Side.LEFT or Side.RIGHT

  • stream – the stream that is printing the node

Returns:

bool

pglast.precedence.operator_precedence(name)

Return the precedence of operator name.

Parameters:

name – the A_Expr.name slot

Returns:

ExprPrec

OPERATOR(schema.op) always has the precedence of Op.

pglast.precedence.special_function_name(node, stream)

Return the qualified name of the special function that stream will use to print node.

Parameters:
  • node – an .ast.Node instance

  • stream – the stream that is printing the node

Returns:

either None or the qualified name of a registered special function

Only the functions whose alternate form changes the precedence of the node matter here: pg_catalog.timezone() is printed as AT TIME ZONE and pg_catalog.is_normalized() as IS ... NORMALIZED, both only when the special_functions option is enabled. Deferring to the stream keeps this in sync with what is actually emitted.

pglast.precedence.subquery_operator_precedence(name)

Return the precedence of operator name, as used in a subquery comparison.

Parameters:

name – the A_Expr.name or SubLink.operName slot

Returns:

ExprPrec

A subquery comparison using one of the LIKE/ILIKE operators is printed in that keyword form, so the operator binds like BETWEEN; everything else behaves as in operator_precedence().