Skip to content

pgparse

Python bindings for libpg_query, exposing PostgreSQL's internal parser to Python. Parse, normalize, and fingerprint SQL statements using the same parser that PostgreSQL itself uses.

Version Coverage License

PostgreSQL Compatibility

pgparse libpg_query PostgreSQL
1.x 17-latest 17

Installation

pip install pgparse

Wheels are provided for Linux (manylinux and musllinux, x86_64 and aarch64) and macOS (arm64) for Python 3.11+ via the stable ABI (abi3). Installing from source requires gcc, make, and the libpg_query build dependencies.

Usage

Parse

Returns the internal PostgreSQL parse tree as a list of statement dicts:

import pgparse

result = pgparse.parse("SELECT * FROM orders WHERE id = 1")
# [{'stmt': {'SelectStmt': {...}}}]

Normalize

Replaces literal values with positional placeholders — useful for query grouping and log analysis:

pgparse.normalize("SELECT * FROM orders WHERE id = 1")
# "SELECT * FROM orders WHERE id = $1"

pgparse.normalize("SELECT * FROM orders WHERE id = 2")
# "SELECT * FROM orders WHERE id = $1"

Fingerprint

Produces a stable hash that is identical for structurally equivalent queries regardless of literal values or formatting:

pgparse.fingerprint("SELECT * FROM orders WHERE id = 1")
# "0357e3db3ead2de761ea5c0f064bfddc0048cad5eb"

pgparse.fingerprint("SELECT * FROM orders WHERE id = 99")
# "0357e3db3ead2de761ea5c0f064bfddc0048cad5eb"  # same fingerprint

Parse PL/pgSQL

Parse a PL/pgSQL function body:

func = """
CREATE FUNCTION sales_tax(subtotal real) RETURNS real AS $$
    BEGIN
        RETURN subtotal * 0.06;
    END;
$$ LANGUAGE plpgsql;
"""
result = pgparse.parse_pgsql(func)

Error Handling

Invalid SQL raises pgparse.PGQueryError with the error message and cursor position:

try:
    pgparse.parse("SELECT FROM WHERE")
except pgparse.PGQueryError as e:
    print(e.message)   # syntax error at or near "WHERE"
    print(e.position)  # 13

Further Reading