Skip to content

Commit b20c1cc

Browse files
authored
Merge pull request #50 from ProxySQL/feat/postgresql-compat-harness
[codex] PostgreSQL compatibility harness foundation
2 parents af1e5b0 + e3f494d commit b20c1cc

45 files changed

Lines changed: 110855 additions & 2 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ on:
55
branches: [main]
66
pull_request:
77
branches: [main]
8+
schedule:
9+
- cron: '17 3 * * 1'
810

911
jobs:
1012
build-and-test:
13+
if: github.event_name != 'schedule'
1114
strategy:
1215
matrix:
1316
os: [ubuntu-22.04, ubuntu-24.04]
@@ -22,6 +25,7 @@ jobs:
2225
run: make -f Makefile clean && make -f Makefile all
2326

2427
macos:
28+
if: github.event_name != 'schedule'
2529
runs-on: macos-latest
2630
steps:
2731
- uses: actions/checkout@v4
@@ -38,6 +42,7 @@ jobs:
3842
run: make -f Makefile clean && make -f Makefile all MYSQL_CFLAGS="-I/opt/homebrew/opt/mysql-client/include"
3943

4044
benchmark:
45+
if: github.event_name != 'schedule'
4146
runs-on: ubuntu-24.04
4247
steps:
4348
- uses: actions/checkout@v4
@@ -58,6 +63,7 @@ jobs:
5863
path: benchmark_results.json
5964

6065
corpus-test:
66+
if: github.event_name != 'schedule'
6167
runs-on: ubuntu-24.04
6268
steps:
6369
- uses: actions/checkout@v4
@@ -96,3 +102,43 @@ jobs:
96102
grep -ohP '"((?:SELECT|INSERT|UPDATE|DELETE|SET|CREATE|ALTER|DROP|EXPLAIN|WITH)[^"]*)"' \
97103
/tmp/sqlparser-rs/tests/sqlparser_postgres.rs 2>/dev/null | \
98104
sed 's/^"//' | sed 's/"$//' | sed 's/\\"/"/g' | ./corpus_test pgsql
105+
106+
pg-compat:
107+
if: github.event_name != 'schedule'
108+
runs-on: ubuntu-24.04
109+
timeout-minutes: 30
110+
env:
111+
PG_COMPAT_CACHE: /tmp/parsersql-pg-compat
112+
steps:
113+
- uses: actions/checkout@v4
114+
115+
- name: Cache PostgreSQL compatibility sources
116+
uses: actions/cache@v4
117+
with:
118+
path: /tmp/parsersql-pg-compat
119+
key: pg-compat-${{ runner.os }}-${{ hashFiles('tests/pg_compat/upstream_pins.json') }}
120+
restore-keys: |
121+
pg-compat-${{ runner.os }}-
122+
123+
- name: Test PostgreSQL compatibility gate
124+
run: make -f Makefile test-pg-compat
125+
126+
pg-compat-full:
127+
if: github.event_name == 'schedule'
128+
runs-on: ubuntu-24.04
129+
timeout-minutes: 45
130+
env:
131+
PG_COMPAT_CACHE: /tmp/parsersql-pg-compat
132+
steps:
133+
- uses: actions/checkout@v4
134+
135+
- name: Cache PostgreSQL compatibility sources
136+
uses: actions/cache@v4
137+
with:
138+
path: /tmp/parsersql-pg-compat
139+
key: pg-compat-${{ runner.os }}-${{ hashFiles('tests/pg_compat/upstream_pins.json') }}
140+
restore-keys: |
141+
pg-compat-${{ runner.os }}-
142+
143+
- name: Validate full PostgreSQL compatibility baseline
144+
run: make -f Makefile pg-compat

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
*.out
3232
*.app
3333

34+
# Local git worktrees
35+
.worktrees/
36+
3437
# Build artifacts
3538
libsqlparser.a
3639
sqlengine
@@ -39,4 +42,6 @@ run_tests_debug
3942
corpus_test
4043
run_bench
4144
run_bench_compare
45+
pg_compat_17
46+
pg_compat_18
4247
bench/sqlparser_rs_bench/target/

Makefile

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ MYSQL_CFLAGS = $(shell mysql_config --cflags 2>/dev/null)
77
MYSQL_LIBS = $(shell mysql_config --libs 2>/dev/null)
88
PG_CFLAGS = -I$(shell pg_config --includedir 2>/dev/null || echo /usr/include/postgresql)
99
PG_LIBS = -L$(shell pg_config --libdir 2>/dev/null || echo /usr/lib/x86_64-linux-gnu) -lpq
10+
PG_COMPAT_CACHE ?= /tmp/parsersql-pg-compat
1011

1112
PROJECT_ROOT = .
1213
SRC_DIR = $(PROJECT_ROOT)/src/sql_parser
@@ -122,12 +123,26 @@ ENGINE_STRESS_TARGET = engine_stress_test
122123
MYSQL_SERVER_SRC = $(PROJECT_ROOT)/tools/mysql_server.cpp
123124
MYSQL_SERVER_TARGET = mysql_server
124125

125-
.PHONY: all lib test test-sqlengine test-sqlengine-in-memory test-sqlengine-single test-sqlengine-sharded bench bench-compare bench-distributed build-corpus-test build-sqlengine engine-stress mysql-server clean
126+
.PHONY: all lib test test-sqlengine test-sqlengine-in-memory test-sqlengine-single test-sqlengine-sharded bench bench-compare bench-distributed build-corpus-test build-sqlengine build-pg-compat pg-compat pg-compat-refresh test-pg-compat engine-stress mysql-server clean
126127

127128
build-corpus-test: $(CORPUS_TEST_TARGET)
128129

129130
build-sqlengine: $(SQLENGINE_TARGET)
130131

132+
build-pg-compat: lib
133+
PG_COMPAT_CACHE=$(PG_COMPAT_CACHE) ./scripts/pg_compat/fetch_libpg_query.sh
134+
python3 ./scripts/pg_compat/run_compat.py build --cache $(PG_COMPAT_CACHE)
135+
136+
test-pg-compat: build-pg-compat
137+
PG_COMPAT_RUNNER=$(PG_COMPAT_CACHE)/bin/pg_compat-18 python3 -m unittest discover -s tests/pg_compat -p 'test_*.py' -v
138+
python3 ./scripts/pg_compat/run_compat.py test --cache $(PG_COMPAT_CACHE)
139+
140+
pg-compat: build-pg-compat
141+
python3 ./scripts/pg_compat/run_compat.py full --cache $(PG_COMPAT_CACHE)
142+
143+
pg-compat-refresh: build-pg-compat
144+
python3 ./scripts/pg_compat/run_compat.py refresh --cache $(PG_COMPAT_CACHE)
145+
131146
all: lib test
132147

133148
lib: $(LIB_TARGET)

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,26 @@ make build-sqlengine # Interactive SQL CLI
6464
make build-corpus-test # Corpus validation harness
6565
```
6666

67+
### PostgreSQL compatibility harness
68+
69+
ParserSQL uses `libpg_query` as the PostgreSQL syntax oracle for compatibility checks. The harness pins `libpg_query` `17-latest` and `18-latest`, extracts accepted PostgreSQL regression statements, and compares ParserSQL behavior against the committed PostgreSQL 18 baseline in [`docs/compatibility/postgresql-18.md`](docs/compatibility/postgresql-18.md).
70+
71+
Compatibility results separate full parser parity from classification coverage:
72+
73+
- `DEEP_SUPPORTED` means ParserSQL accepted the statement with the expected statement type and a full AST.
74+
- `CLASSIFIED_ONLY` means ParserSQL recognized the top-level statement class, but did not produce full deep parser parity for that SQL.
75+
- `PARTIAL`, `ERROR`, `TRAILING_INPUT`, and `TYPE_MISMATCH` are tracked separately in the committed baseline.
76+
77+
The report includes the full PostgreSQL 18 backlog, the PG17-to-PG18 release delta, statement routing coverage, and reviewed structural grammar/keyword changes.
78+
79+
```bash
80+
make test-pg-compat # Build the pinned oracle runner, run harness unit tests, and replay committed CI cases
81+
make pg-compat # Run the full pinned PG17/PG18 comparison against the committed baseline
82+
make pg-compat-refresh # Regenerate expected_results.jsonl, ci_cases.jsonl, and docs/compatibility/postgresql-18.md
83+
```
84+
85+
`PG_COMPAT_CACHE` controls where external `libpg_query` and PostgreSQL source checkouts are cached. It defaults to `/tmp/parsersql-pg-compat`.
86+
6787
### Interactive CLI (`sqlengine`)
6888

6989
```bash

docs/benchmarks/REPRODUCING.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Step-by-step instructions to reproduce all comparison benchmarks from scratch on
99
```bash
1010
# Required tools
1111
sudo apt-get update
12-
sudo apt-get install -y build-essential git curl
12+
sudo apt-get install -y build-essential git curl tar bzip2
1313

1414
# Rust (for sqlparser-rs benchmark)
1515
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
@@ -19,6 +19,9 @@ source ~/.cargo/env
1919
g++ --version # need GCC 8+ (C++17 support)
2020
cargo --version # need Rust 1.70+
2121
git --version
22+
curl --version
23+
tar --version
24+
python3 --version
2225
```
2326

2427
---
@@ -76,6 +79,44 @@ ls -la third_party/libpg_query/libpg_query.a
7679

7780
---
7881

82+
## PostgreSQL Compatibility Harness
83+
84+
The PostgreSQL compatibility harness uses pinned `libpg_query` builds as the syntax oracle. It compares ParserSQL against PostgreSQL 17 and PostgreSQL 18 regression SQL, writes a committed PostgreSQL 18 baseline, and reports the PG17-to-PG18 syntax delta in `docs/compatibility/postgresql-18.md`.
85+
86+
Required external tools:
87+
88+
```text
89+
git
90+
curl
91+
tar with bzip2 support
92+
python3
93+
C/C++ compiler
94+
make
95+
```
96+
97+
`PG_COMPAT_CACHE` controls where external sources and built oracle runners are cached. It defaults to `/tmp/parsersql-pg-compat`.
98+
99+
```bash
100+
# Fast deterministic gate: unit tests plus committed CI cases
101+
make test-pg-compat
102+
103+
# Full pinned PG17/PG18 comparison against committed expected_results.jsonl
104+
make pg-compat
105+
106+
# Refresh committed artifacts after intentionally updating pins or mappings
107+
make pg-compat-refresh
108+
```
109+
110+
The harness result model distinguishes parser depth from statement routing:
111+
112+
- `DEEP_SUPPORTED` means ParserSQL accepted the SQL with the expected statement type and a full AST.
113+
- `CLASSIFIED_ONLY` means ParserSQL recognized the top-level statement class, but did not reach full parser parity for that SQL.
114+
- `PARTIAL`, `ERROR`, `TRAILING_INPUT`, and `TYPE_MISMATCH` are committed baseline outcomes that must not regress silently.
115+
116+
The refresh target updates `tests/pg_compat/expected_results.jsonl`, `tests/pg_compat/ci_cases.jsonl`, and `docs/compatibility/postgresql-18.md`.
117+
118+
---
119+
79120
## Step 4: Build the comparison benchmark
80121

81122
```bash

0 commit comments

Comments
 (0)