pglast Documentation

repository·v8·Indexed 18 days ago

https://github.com/lelit/pglast

pglast is a Python 3 module (version 8.4) that exposes the PostgreSQL statement parse tree as an Abstract Syntax Tree (AST) using libpg_query. It provides tools to parse PL/pgSQL blocks via parse_plpgsql(), format SQL with prettify(), and split multiple statements with split(). The library includes a comprehensive set of Python data classes in pglast.ast that wrap PostgreSQL C structures, allowing for the programmatic inspection and mutation of parser nodes such as AlterTableStmt, ColumnDef, and CommonTableExpr.

Tokens
63.1K
Snippets
314
Records
399
Agent score
64%

What's inside pglast

  1. Overview of pglast

    v8
    pglast is a Python 3 module that provides access to the parse tree (Abstract Syntax Tree or AST) of PostgreSQL statements. It achieves this by using libpg_query (a standalone static library version of the standard PostgreSQL parser) to extract the tree and represent it as a set of interconnected nodes.
  2. Pretty print DDL nodes with pglast.printers.ddl

    v8
    The pglast.printers.ddl module provides a suite of functions to pretty print various PostgreSQL Data Definition Language (DDL) AST nodes to an output stream. Each function is designed to handle a specific node type (e.g., AlterTableStmt, CreateStmt, AlterRoleStmt) and converts the AST representation back into a human-readable SQL string.
  3. Use pglast.stream for AST serialization

    v8

    The pglast.stream module provides the serialization machinery for converting PostgreSQL ASTs (Abstract Syntax Trees) into formatted text or raw streams. It is primarily used to transform parsed tree structures back into valid, human-readable, or machine-readable SQL statements.

    Key components include:

    • OutputStream: The base class for stream-based serialization.
    • RawStream: A stream implementation that outputs the raw, unformatted representation of the AST.
    • IndentedStream: A stream implementation that produces formatted, indented SQL text, useful for prettifying statements.
  4. Use pglast.enums for PostgreSQL constant values

    v8

    The pglast.enums module provides enumerated constants that give semantic meaning to scalar values found within various PostgreSQL AST nodes. These constants are automatically extracted from PostgreSQL headers and are used to identify specific types, access methods, or configuration settings within the parsed tree.

    Instead of using raw integer or string values, you should use the corresponding enum from pglast.enums to ensure your code is robust and matches the PostgreSQL internal logic.

  5. Understand the pglast.ast Node base class

    v8

    The pglast.ast.Node class is the abstract base class for all PostgreSQL parser nodes in pglast. Every concrete node class inherits from Node and provides the following common behaviors:

    • Comparison: Nodes can be compared for equality using __eq__.
    • Serialization: Nodes can be serialized (converted back to a string representation) by calling the instance as a function (__call__).
    • Mutation: Nodes can be altered by setting attributes (__setattr__).
    # Example of the common behaviors of a Node
    # (Assuming 'node' is an instance of a concrete Node class)
    
    # Comparison
    if node == other_node:
        pass
    
    # Serialization (calling the node instance)
    sql_string = node()
    
    # Alteration
    node.some_attribute = new_value
  6. Fix UTF-8 byte offsets to Unicode character indices

    v8

    The underlying libpg_parse library operates on UTF-8 strings and emits token location values as offsets within the UTF-8 byte array. If your SQL contains multi-byte characters (like emojis or accented letters), these byte offsets will not match Python's string indexing.

    Use the Displacements(unicode_string) helper class to map a UTF-8 byte offset to the correct Unicode character index.

    from pglast.parser import Displacements
    
    stmt = 'select alias.bar as alìbàbà from foo as alias'
    # ... assume 'loc' is a byte offset from a parsed JSON object ...
    d = Displacements(stmt)
    adjloc = d(loc)
    print(stmt[adjloc:adjloc+3])
  7. Serialize AST nodes to text or indented formats

    v8

    The module provides two ways to transform a Node into a textual representation:

    1. Raw representation: Uses pglast.stream.RawStream to produce a raw textual output.
    2. Prettified representation: Uses pglast.stream.IndentedStream to produce a formatted, indented output. This prettified format is also available via the pgpp CLI tool.
  8. Traverse and modify the AST using `Visitor`

    v8

    To inspect or transform the AST, subclass pglast.visitors.Visitor and implement the visit method or specific visit_<NodeName> methods.

    • Inspection: Use visit to perform actions on every node (e.g., counting node types).
    • Transformation/Deletion: Returning the pglast.visitors.Delete object from a visit method will remove that node (and its subtree) from the AST during the visitor pass.

    Example of deleting a specific constraint type:

    from pglast import parse_sql, enums
    from pglast.visitors import Visitor, Delete
    
    class DropNullConstraint(Visitor):
        def visit_Constraint(self, ancestors, node):
            if node.contype == enums.ConstrType.CONSTR_NULL:
                return Delete
    
    raw = parse_sql('create table foo (a integer null, b integer not null)')
    modified_raw = DropNullConstraint()(raw)
  9. Use special function printers to restore SQL syntax

    v8

    By default, the PostgreSQL parser translates certain SQL constructs into standard function calls (e.g., EXTRACT(YEAR FROM col) becomes pg_catalog.date_part('year', col)).

    To preserve the original SQL syntax instead of the translated function calls when printing an AST, you must enable the special_functions option on the output stream. This is done by setting special_functions=True in the pglast.printers.sfuncs module context via the RawStream configuration.

  10. Install pglast from source

    v8

    To install from the source repository, clone the repository recursively (to ensure submodules like libpg_query are included) and then install using pip from the local directory.

    $ git clone https://github.com/lelit/pglast.git --recursive
    $ pip install ./pglast
  11. Manage development tasks with makefiles

    v8

    The project uses makefiles to implement common development operations. You can use make help to view a brief table of contents of available commands.

    To run the test suite, the project uses pytest and aims for high coverage (nearly 99% of source lines).

    make help