Library / SDK
pganalyze/libpg_query avatar
pganalyze/libpg_query

libpg_query: PostgreSQL Parsing Outside the Server

C library for accessing the PostgreSQL parser outside of the server environment

1,488 stars231 forksCBSD-3-Clause

At a glance

What is it?
libpg_query is a BSD-3-Clause C library for parsing, scanning, and fingerprinting PostgreSQL queries without starting a PostgreSQL server. It is aimed at language bindings, analysis tools, and applications that need PostgreSQL-compatible syntax data.
Who is it for?
Adopt libpg_query when a C application needs PostgreSQL's parser or scanner without a server process, especially if it is building another language binding or query-analysis feature. Do not choose it for semantic SQL execution, catalog lookup, or validation that depends on a live database.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.

Editorial analysis

libpg_query and the PostgreSQL parse tree

libpg_query solves a specific integration problem: applications often need to understand PostgreSQL SQL syntax without linking a PostgreSQL server or maintaining a separate SQL grammar. The README says that the library uses actual PostgreSQL server source to parse queries and return PostgreSQL's internal parse tree. That makes it relevant to editor tooling, query inspection, normalization, language packages, and services that process SQL as text.

The intended audience includes C developers and maintainers of bindings such as the README's Ruby, Go, Rust, Node, and Python integrations. The library is not presented as a database driver. It does not connect to a database, execute statements, or resolve tables and columns. It works at the parser and scanner layers, so an application must still arrange its own access to server metadata if it needs semantic validation.

The C API returns a `PgQueryParseResult` whose `parse_tree` field contains a JSON representation of the PostgreSQL parse tree. For `SELECT 1`, the documented output includes a `SelectStmt`, a target list, an `A_Const`, source locations, and a parse-tree version. Source locations are part of the returned structure, which can help tools map syntax information back to input text.

Parsing, scanning, and fingerprinting as separate APIs

The library exposes more than one PostgreSQL processing layer. `pg_query_parse` performs parsing and returns the parse tree. `pg_query_scan_tokens` runs the underlying PostgreSQL scanner and returns token objects, including byte offsets, token values, and keyword classifications. `pg_query_scan` provides the same token information serialized as a Protobuf `ScanResult`, with the vendored upb runtime included in `libpg_query.a`.

The scanner example shows why this distinction matters. Its input contains `SELECT`, identifiers that resemble keywords, and a comment. The output separates each lexical item, reports its start and end positions, and identifies its keyword category. Whitespace does not appear as a token. The README specifically warns that token numbers are PostgreSQL grammar values that change between PostgreSQL versions, so callers should compare `PgQueryToken` values by name rather than by numeric value.

Fingerprinting is a third operation. `pg_query_fingerprint` returns `fingerprint_str`, intended to identify similar queries while normalizing differences such as constant values and formatting. The README describes the fingerprint mechanism as a superset of PostgreSQL's `queryid` mechanism. It also notes a PostgreSQL 18 change affecting schema names and table aliases in `FROM` clauses when calculating `queryid`, so callers should account for version-specific behavior instead of assuming identical semantics across PostgreSQL releases.

Building libpg_query from the default branch

The documented Linux and macOS installation path clones the default `18-latest` branch and runs `make`. The build compiles parts of PostgreSQL, and the README warns that this can take up to three minutes. A production build should use a specific Git tag from `CHANGELOG.md`, because a moving branch is less suitable as a fixed dependency.

The Makefile identifies PostgreSQL 18.6 as `PG_VERSION`, version 18.1.0 as the library `VERSION`, and `18.1.0` as the release represented by this checkout. It builds both a static archive named `libpg_query.a` and a platform-specific shared library. On Darwin the shared-library names use `.dylib`; on other systems they use `.so`. The build includes source files from `src/`, PostgreSQL sources under `src/postgres/`, xxhash, and generated upb sources.

Windows builds use a separate makefile. The documented command is below. The repository also includes `Makefile.msvc`, so Visual Studio users should not assume that the Unix command is the supported Windows path.

A first C program and library compile command

The following is the README's minimal parser example. It allocates a parse result, prints the JSON parse tree, releases the result with `pg_query_free_parse_result`, and returns success. The release call is part of the example, not an optional convenience: result objects contain memory owned by the caller and should be freed through the matching library function.

The source file must be compiled with the repository include directory and linked with `libpg_query`. The command shown by the README is:

c
#include <pg_query.h>
#include <stdio.h>

int main() {
  PgQueryParseResult result;

  result = pg_query_parse("SELECT 1");

  printf("%s\n", result.parse_tree);

  pg_query_free_parse_result(result);

  return 0;
}

Save the code as the example source used by your project, then compile it from the repository root with:

bash
cc -Ilibpg_query -Llibpg_query example.c -lpg_query

The README does not document an additional runtime library path flag for this command. If the linker cannot locate the built library, the issue is in the build output or linker search path, not a new parser option. The documented output is a JSON object with `version`, `stmts`, and the PostgreSQL `SelectStmt` structure.

What the C API does not provide

The central limitation is scope. libpg_query answers syntax questions by exposing PostgreSQL parsing and scanning, but the repository does not present it as a replacement for a PostgreSQL connection or execution engine. A query can parse successfully without referring to an existing schema, table, column, role, or extension. Applications that need those checks must use another layer.

There is another portability constraint. The output follows PostgreSQL internals, and token enum numbers change between PostgreSQL versions. A consumer should therefore treat PostgreSQL version compatibility as part of its integration contract. The default branch is named `18-latest`, while the README also documents releases for PostgreSQL 17, indicating that consumers may need to select or build a version-specific branch or tag for their target SQL grammar.

The README excerpt does not document a general deparse API, even though `postgres_deparse.h` appears in the repository entries. It also does not promise stable C ABI guarantees in the public documentation. For those reasons, callers should inspect the public headers and release notes rather than infer additional capabilities from filenames.

Comparing libpg_query with a live PostgreSQL workflow

A real alternative is to run PostgreSQL itself and use server-side SQL facilities or a client library. The difference is architectural. A server-based workflow can resolve catalog objects, enforce permissions, execute statements, and report errors in the context of an actual database. libpg_query performs local parsing and lexical analysis through PostgreSQL source code, without requiring a running server environment.

That difference makes libpg_query useful when the input must be parsed before a database is available, such as in syntax-aware tooling or a language binding. It also creates a boundary: parse success is not execution success. A caller that needs semantic validation cannot stop at `pg_query_parse`; it must connect to a database or otherwise supply the relevant catalog and execution context.

The repository's own README identifies several wrappers built around libpg_query. Those projects are alternatives at the integration level for developers who prefer Ruby, Go, Rust, Node, or Python APIs. They do not represent a different parsing principle if they delegate to this library. Teams choosing among them should first determine whether their requirement is a C dependency, a specific language API, or PostgreSQL server semantics.

Maintenance, licensing, and upgrade work

The repository is not archived, and its last push was on 2026-10-02. Recent releases include `18.1.0`, `17-6.2.5`, and `17-6.2.4`, all dated 2026-09-30. This indicates recent repository activity in the recorded history, but the project still requires version selection as part of maintenance. The README's advice to use a specific Git tag for production is especially relevant because the default branch is named `18-latest`.

The declared license is BSD-3-Clause. That is the repository's stated licensing information. Consumers still need to review the `LICENSE` file and account for the bundled or compiled PostgreSQL and third-party sources in their own distribution process. The license text alone does not answer every compliance question, so this review does not offer legal advice.

Upgrades can affect grammar behavior, token numbering, parse-tree fields, and build requirements. The PostgreSQL version in the Makefile and the version-specific release branch should be checked against the SQL accepted by the target server. A release upgrade should therefore include parser output review, example recompilation, and tests for fingerprints and error handling.

Editorial conclusion

Adopt libpg_query when a C application needs PostgreSQL's parser or scanner without a server process, especially if it is building another language binding or query-analysis feature. Do not choose it for semantic SQL execution, catalog lookup, or validation that depends on a live database. Verify first that the selected PostgreSQL version matches the SQL your users submit, then inspect the build, parser output, and memory-release APIs for your deployment.

Frequently asked questions

How do I install libpg_query?

Clone the `18-latest` branch, change into the repository, and run `make`. The README says this may take up to three minutes because parts of PostgreSQL are compiled. For production, it recommends using a specific Git tag from `CHANGELOG.md`.

What does libpg_query return when parsing SQL?

It returns a `PgQueryParseResult`, and its `parse_tree` field contains a JSON representation of PostgreSQL's internal parse tree. The example prints that field and then calls `pg_query_free_parse_result`.

Can libpg_query scan SQL without parsing it?

Yes. `pg_query_scan_tokens` uses the underlying PostgreSQL scanner and returns token positions, token values, and keyword classifications. `pg_query_scan` returns the same tokens serialized as a Protobuf `ScanResult`.

Does libpg_query validate queries against a database schema?

The README describes parsing and scanning, not database connection or execution. It does not document catalog resolution or semantic validation, so parse success should not be treated as confirmation that referenced tables, columns, roles, or other server objects exist.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. pganalyze/libpg_query on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pganalyze-libpg-query.svg)](https://hysenlabs.com/projects/pganalyze-libpg-query)

Was this useful?