Skip to main content

PyGoSQLX

Python bindings for GoSQLX -- a high-performance SQL parser written in Go. Parses, validates, formats, and analyzes SQL statements at native speed via a shared library (ctypes FFI).

Powered by Go's compiled performance, PyGoSQLX is 100x+ faster than pure Python SQL parsers while providing a simple, Pythonic API.

Installation

pip install pygosqlx

Prebuilt wheels bundle the native libgosqlx library, so no Go toolchain is needed. pygosqlx is versioned in lockstep with GoSQLX: each GoSQLX release (starting with 1.16.0) publishes the matching pygosqlx version, whose wheels bundle the library built from that release.

Wheels are available for Python 3.10-3.14 on:

Platform Architectures Wheel tag
Linux (glibc) x86_64, aarch64 manylinux_2_17 (manylinux2014; glibc 2.17+, built on manylinux_2_28)
macOS 13+ x86_64, arm64 macosx_13_0
Windows AMD64 win_amd64

There are no wheels for musl-based Linux (Alpine) or 32-bit platforms. On those, pip falls back to the source distribution, which installs the Python package without the native library; build it as described below and point GOSQLX_LIB_PATH at it.

Building from source

Requires a Go toolchain matching the repository's go.mod (Go 1.26+) with cgo enabled (a C compiler on PATH).

git clone https://github.com/ajitpratap0/GoSQLX.git
cd GoSQLX/pkg/cbinding
./build.sh          # writes python/pygosqlx/lib/libgosqlx.{so,dylib}
cd ../../python
pip install .       # or: pip install -e ".[dev]" for development

build.sh compiles the Go code into a shared library (libgosqlx.so on Linux, libgosqlx.dylib on macOS, libgosqlx.dll on Windows via MSYS2/MinGW) and places it in python/pygosqlx/lib/, where pip install . bundles it. Use OUTPUT_DIR=/path/to/output ./build.sh to write it elsewhere.

Building a wheel without the library fails on purpose, so pip install on a platform with no prebuilt wheel (for example musl or 32-bit Linux) stops with an error instead of installing a package that cannot load. To install without a bundled library and supply one at runtime instead, set PYGOSQLX_ALLOW_MISSING_LIB=1 for the install and point GOSQLX_LIB_PATH at the library:

PYGOSQLX_ALLOW_MISSING_LIB=1 pip install pygosqlx
export GOSQLX_LIB_PATH=/path/to/libgosqlx.so

Quick Start

import pygosqlx

# Parse SQL - raises ParseError on invalid SQL
result = pygosqlx.parse("SELECT id, name FROM users WHERE active = true")
print(result.statement_count)  # 1
print(result.statement_types)  # ['SELECT']

# Validate SQL syntax
is_valid = pygosqlx.validate("SELECT * FROM users")
print(is_valid)  # True

is_valid = pygosqlx.validate("SELEC * FORM users")
print(is_valid)  # False

# Validate with detailed error info
detail = pygosqlx.validate_detailed("SELEC * FORM users")
if not detail.valid:
    print(detail.error)        # Error message
    print(detail.error_line)   # Line number
    print(detail.error_column) # Column number

# Format SQL
formatted = pygosqlx.format("select id,name from users where id=1")
print(formatted)

# Extract table names
tables = pygosqlx.extract_tables(
    "SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id"
)
print(tables)  # ['users', 'orders']

# Extract column names
columns = pygosqlx.extract_columns("SELECT id, name, email FROM users")
print(columns)  # ['id', 'name', 'email']

# Extract function calls
functions = pygosqlx.extract_functions(
    "SELECT COUNT(*), AVG(price) FROM orders"
)
print(functions)  # ['COUNT', 'AVG']

# Extract all metadata at once
meta = pygosqlx.extract_metadata(
    "SELECT u.name, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.name"
)
print(meta.tables)     # ['users', 'orders']
print(meta.columns)    # ['name', 'id']
print(meta.functions)  # ['COUNT']
# Qualified names available too:
for qn in meta.tables_qualified:
    print(f"{qn.schema}.{qn.name}" if qn.schema else qn.name)

Dialects

Every parsing function takes an optional keyword-only dialect= argument. Without it (or with dialect=None) the default parser is used, exactly as in earlier releases.

print(pygosqlx.dialects())
# ['generic', 'postgresql', 'mysql', 'mariadb', 'sqlserver', 'oracle',
#  'sqlite', 'snowflake', 'bigquery', 'redshift', 'clickhouse']

sql = "SELECT TOP 5 [id] FROM [dbo].[users]"
pygosqlx.validate(sql)                       # False - not generic SQL
pygosqlx.validate(sql, dialect="sqlserver")  # True
pygosqlx.extract_tables(sql, dialect="sqlserver")  # ['dbo.users']
pygosqlx.format("SELECT `id` FROM `users`", dialect="mysql")

# An unknown dialect raises UnsupportedDialectError (also a ValueError)
pygosqlx.parse("SELECT 1", dialect="postgres")  # use "postgresql"

Linting

lint() runs the same rule set as the gosqlx lint CLI command (L001-L010: whitespace, indentation, line length, column alignment, keyword case, comma placement, aliasing). SQL that does not parse is still linted by the text and token rules.

result = pygosqlx.lint("select id from users  ", max_line_length=100)
for v in result.violations:
    print(v.rule, v.severity, v.line, v.column, v.message)
# L001 warning 1 21 Line has trailing whitespace
# L007 warning 1 1 Keyword 'select' should be uppercase: 'SELECT'
# ...
print(result.is_clean, result.violation_count)

Security scanning

security_scan() looks for SQL injection patterns (tautologies, comment bypasses, stacked queries, UNION injection, time-based and out-of-band techniques, dangerous functions). The scan works on the raw text, so payloads that are not valid SQL are scanned too.

scan = pygosqlx.security_scan("SELECT * FROM users WHERE id = 1 OR 1=1 --")
print(scan.is_clean, scan.has_critical)  # False True
for f in scan.findings:
    print(f.severity, f.pattern, f.description)

Transpiling

pygosqlx.transpile(
    "CREATE TABLE t (id INT AUTO_INCREMENT PRIMARY KEY)", "mysql", "postgresql"
)
# 'CREATE TABLE t (id SERIAL PRIMARY KEY)'

Dedicated rewrites exist for MySQL to PostgreSQL, PostgreSQL to MySQL and PostgreSQL to SQLite. Other pairs are parsed with the source dialect and re-rendered without rewrites.

Library compatibility

The functions and the dialect= argument added in 1.16.0 need a shared library built from a matching GoSQLX checkout. With an older library, calls without dialect= keep working, while dialect=, lint(), security_scan(), transpile() and dialects() raise GoSQLXError asking you to rebuild the library.

Error Handling

from pygosqlx import parse, validate, extract_tables
from pygosqlx.exceptions import ParseError, FormatError, GoSQLXError

# parse() raises ParseError on invalid SQL
try:
    result = parse("SELECT * FORM users")
except ParseError as e:
    print(f"Error: {e.message}")
    print(f"At line {e.line}, column {e.column}")

# validate() returns a boolean (never raises)
if not validate("BAD SQL"):
    print("Invalid SQL")

# extract_*() functions raise ParseError on invalid SQL
try:
    tables = extract_tables("NOT VALID SQL")
except ParseError as e:
    print(f"Parse error: {e}")

# All exceptions inherit from GoSQLXError
try:
    parse("???")
except GoSQLXError as e:
    print(f"Caught: {e}")

API Reference

Function Returns Description
parse(sql, *, dialect=None) ParseResult Parse SQL; raises ParseError on failure
validate(sql, *, dialect=None) bool Check if SQL is syntactically valid
validate_detailed(sql, *, dialect=None) ValidationResult Validate with error line/column details
format(sql, *, dialect=None) str Format/pretty-print a SQL statement
extract_tables(sql, *, dialect=None) list[str] Extract all table names
extract_columns(sql, *, dialect=None) list[str] Extract all column names
extract_functions(sql, *, dialect=None) list[str] Extract all function calls
extract_metadata(sql, *, dialect=None) Metadata Extract tables, columns, functions, and qualified names
lint(sql, *, dialect=None, max_line_length=None) LintResult Lint with the gosqlx lint rule set (L001-L010); max_line_length defaults to 100
security_scan(sql) SecurityScanResult Scan for SQL injection patterns
transpile(sql, from_dialect, to_dialect) str Convert SQL between dialects; raises TranspileError on failure
dialects() list[str] Names accepted by every dialect argument
version() str Get the GoSQLX library version

dialect must be one of the names returned by dialects(); an unknown name raises UnsupportedDialectError.

Data Types

Type Fields
ParseResult statement_count: int, statement_types: list[str]
ValidationResult valid: bool, error: str?, error_line: int?, error_column: int?
Metadata tables, columns, functions, tables_qualified, columns_qualified
QualifiedName name: str, schema: str, table: str
LintResult violations: list[LintViolation]; properties violation_count, is_clean
LintViolation rule, rule_name, severity, message, line, column, suggestion, can_auto_fix
SecurityScanResult findings: list[SecurityFinding], total_count, critical_count, high_count, medium_count, low_count; properties is_clean, has_critical, has_high
SecurityFinding severity, pattern, description, risk, line: int?, column: int?, sql, suggestion

Exceptions

Exception Base When
GoSQLXError Exception Base for all PyGoSQLX errors
ParseError GoSQLXError SQL parsing fails
FormatError GoSQLXError SQL formatting fails
ValidationError GoSQLXError SQL validation fails
TranspileError GoSQLXError transpile() cannot parse or rewrite the SQL
UnsupportedDialectError GoSQLXError, ValueError A dialect argument is not a supported dialect (code is E4002)

All exceptions have message, code, line, and column attributes.

Platform Support

Platform Library Prebuilt wheel From source
Linux x86_64, aarch64 (glibc) .so Yes (glibc 2.17+) Yes
macOS x86_64, arm64 .dylib Yes (macOS 13+) Yes
Windows AMD64 .dll Yes Yes (MSYS2/MinGW)
Other (musl, 32-bit, ...) - No Where Go supports -buildmode=c-shared

Performance

PyGoSQLX calls into compiled Go code via ctypes, avoiding the overhead of pure Python parsing. Typical performance characteristics:

  • 1M+ operations/sec for simple queries
  • Sub-microsecond validation for short SQL statements
  • Zero-copy tokenization in the Go layer
  • Object pooling for minimal GC pressure

This makes PyGoSQLX suitable for high-throughput use cases such as SQL proxies, query analyzers, and CI/CD validation pipelines.

Development

Running tests

cd python
pytest -v                    # All tests
pytest tests/test_types.py   # Type/exception tests (no shared library needed)
pytest tests/test_integration.py  # Integration tests (requires shared library)
pytest --cov=pygosqlx        # With coverage

To run the suite against an installed wheel instead of the checkout (as the release CI does):

pip install pygosqlx pytest   # or a locally built wheel
cd /tmp && PYGOSQLX_TEST_INSTALLED=1 python -m pytest --import-mode=importlib /path/to/GoSQLX/python/tests

Releasing

Wheels for every supported platform and an sdist are built and tested by .github/workflows/pygosqlx-release.yml on each pull request that touches python/ or pkg/. Pushing the GoSQLX release tag vX.Y.Z publishes them to PyPI through Trusted Publishing, so bump pyproject.toml and __version__ in the release PR. Python-only follow-ups use a pygosqlx-vX.Y.Z.postN tag. Either tag must match pyproject.toml and point at a commit on main; tag pushes are the only path to PyPI. A manual dispatch can publish a dry run to TestPyPI. See the workflow header for the one-time PyPI setup.

Project structure

python/
  pygosqlx/
    __init__.py       # Package entry point, public API
    core.py           # ctypes bindings to the Go shared library
    exceptions.py     # Custom exception hierarchy
    py.typed          # PEP 561 type hint marker
    lib/              # Shared library output directory (built artifacts)
  tests/
    test_types.py                  # Type and exception tests (no shared library needed)
    test_package_version.py        # Version metadata consistency
    test_integration.py            # Integration tests with shared library
    test_dialect_and_analysis.py   # dialect=, lint, security_scan, transpile, dialects
    test_installed_wheel.py        # Installed-wheel checks (PYGOSQLX_TEST_INSTALLED=1)
  scripts/
    install-go-linux.sh  # Pinned, checksum-verified Go install for manylinux CI
  pyproject.toml      # Package metadata and build config
  setup.py            # Shim that tags wheels per platform (no metadata)

License

Apache-2.0. See the LICENSE file.

Metadata

Release files for pygosqlx 1.16.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pygosqlx 1.16.0
File Size Uploaded Provenance
pygosqlx-1.16.0.tar.gz 33.7 kB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for pygosqlx 1.16.0
File
pygosqlx-1.16.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
pygosqlx-1.16.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
pygosqlx-1.16.0-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl Python 3 none Linux glibc 2.5+ x86-64, Linux glibc 2.17+ x86-64 Details
pygosqlx-1.16.0-py3-none-macosx_13_0_x86_64.whl Python 3 none macOS 13.0+ x86-64 Details
pygosqlx-1.16.0-py3-none-macosx_13_0_arm64.whl Python 3 none macOS 13.0+ ARM64 Details

Total release size: 14.3 MB

Release files / pygosqlx-1.16.0.tar.gz

Download URL pygosqlx-1.16.0.tar.gz
Size 33.7 kB
Tags Source
SHA-256 checksum
How to use checksums
62653152691edeafd1640c9063457a4b9aa1f698b52b5237409aebd69014531c
BLAKE2b-256 checksum
How to use checksums
6bdb581bfc5ee34d2d1b657c199feb8045b4d21052321f1e838ad2a68dde0220
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / pygosqlx-1.16.0-py3-none-win_amd64.whl

Download URL pygosqlx-1.16.0-py3-none-win_amd64.whl
Size 3.6 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
db2c4e636e8e4d1052c53571f350cf81d2a8c6cd90729e5c929522e5c5438464
BLAKE2b-256 checksum
How to use checksums
ee5db08ce6d27f0ef9a6dd5f48815cbb3e53b880426ddeb9999429abcb31a859
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / pygosqlx-1.16.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl

Download URL pygosqlx-1.16.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
Size 3.2 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
14a262a786fa1021a461ede4cd7846b30b660a4c9d7df93b63693facdbc87d5e
BLAKE2b-256 checksum
How to use checksums
4847b228375f85a121684f20d52695364ac9229ed45ffa1320d22402bace69c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / pygosqlx-1.16.0-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl

Download URL pygosqlx-1.16.0-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Size 3.6 MB
Tags Linux glibc 2.17+ x86-64 Linux glibc 2.5+ x86-64 Python 3
SHA-256 checksum
How to use checksums
4acae8ee52916abcc8584554cbe066f19e574ae3135ba797d54050b42be2b445
BLAKE2b-256 checksum
How to use checksums
4539ebd12bd9970981c2d912f8c0b41b378bb8375c7e8e2a58b79c81eec8f3a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / pygosqlx-1.16.0-py3-none-macosx_13_0_x86_64.whl

Download URL pygosqlx-1.16.0-py3-none-macosx_13_0_x86_64.whl
Size 2.0 MB
Tags Python 3 macOS 13.0+ x86-64
SHA-256 checksum
How to use checksums
76ff1d45683f621b0014d9ad4538e5abeb13890565349de96e1b02a8c640a91e
BLAKE2b-256 checksum
How to use checksums
1184fd0ee3cb8e4a3075c48471604589c4cea8b38d9a9d0495283dd55f0671a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / pygosqlx-1.16.0-py3-none-macosx_13_0_arm64.whl

Download URL pygosqlx-1.16.0-py3-none-macosx_13_0_arm64.whl
Size 1.8 MB
Tags Python 3 macOS 13.0+ ARM64
SHA-256 checksum
How to use checksums
590ca2377cd0adaa033f90521d836e154fb2641a49f6b1ce5a0e5b4bc6d18ea7
BLAKE2b-256 checksum
How to use checksums
83433637d34d633c168f6558c77dc1b9e8200ea61cb9a4f94916aa05c4ef4c6c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for pygosqlx 1.16.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 6 files in this release have been uploaded with provenance metadata.

Select from 6 files

Attestation for pygosqlx-1.16.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.16.0 This release

6 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page