diff --git a/.gitmodules b/.gitmodules index 31bcc97..40c87c7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "libpg_query"] path = libpg_query - url = https://github.com/pgdogdev/libpg_query + url = https://github.com/pganalyze/libpg_query + branch = 18-latest diff --git a/build.rs b/build.rs index 9e54419..c8cb051 100644 --- a/build.rs +++ b/build.rs @@ -103,6 +103,7 @@ fn main() { let mut bindgen = bindgen .allowlist_item("Node") .allowlist_item("MemoryContext") + .allowlist_item("equal") .allowlist_item("pg_query_init") .allowlist_item("AllocSetContextCreateInternal") .allowlist_item("ALLOCSET_DEFAULT_MINSIZE") @@ -163,13 +164,14 @@ fn main() { ) .file(out_dir.join("wrap_static_fns.c")) .file(build_dir.join("copy_pg_error.c")) - // Unfortunately, the linker expects protobuf functions to be present - // even if we're never using them - .file(c_dir.join("vendor/protobuf-c/protobuf-c.c")) + .file(c_dir.join("vendor/upb/upb.c")) + .file(c_dir.join("vendor/upb/third_party/utf8_range/utf8_range.c")) .file(c_dir.join("vendor/xxhash/xxhash.c")) - .file(c_dir.join("protobuf/pg_query.pb-c.c")) + .file(c_dir.join("protobuf/pg_query.upb_minitable.c")) .include(&*c_dir) .include(c_dir.join("vendor")) + .include(c_dir.join("vendor/upb")) + .include(c_dir.join("vendor/upb/third_party/utf8_range")) .include(c_dir.join("src/postgres/include")) .include(c_dir.join("src/include")) .include(build_dir) diff --git a/libpg_query b/libpg_query index cbab26f..aa71ad9 160000 --- a/libpg_query +++ b/libpg_query @@ -1 +1 @@ -Subproject commit cbab26f1a1e9d46a87e6464eca221751d489351c +Subproject commit aa71ad962b654c1d608c687232c047e48dba6452 diff --git a/src/deparse.rs b/src/deparse.rs index d289212..2acfde9 100644 --- a/src/deparse.rs +++ b/src/deparse.rs @@ -91,6 +91,37 @@ fn test_deparse() { run_test("SELECT (ts -> 'a') AT TIME ZONE tz FROM s"); run_test("SELECT ts AT TIME ZONE (a -> 'b') FROM s"); run_test("SELECT ts AT TIME ZONE (tz || 'x') FROM s"); + run_test( + "SELECT ((summary ->> 'ts')::timestamptz AT TIME ZONE (summary -> 'stop' ->> 'tz'))::date AS d FROM s", + ); +} + +#[test] +fn deparse_ast() { + fn run_test(query: &str) { + let original = crate::parse(query).unwrap(); + let stmt = original.first().unwrap(); + let deparsed = deparse(stmt).unwrap(); + let reparsed = crate::parse(deparsed.as_str()).unwrap(); + let reparsed_stmt = reparsed.first().unwrap(); + + assert!( + unsafe { + crate::raw::equal( + std::ptr::from_ref(stmt).cast(), + std::ptr::from_ref(reparsed_stmt).cast(), + ) + }, + "{query}\n{}", + deparsed.as_str() + ); + } + + run_test("SELECT (a + b) * c FROM t"); + run_test("SELECT a - (b - c) FROM t"); + run_test("SELECT (a OR b) AND c FROM t"); + run_test("SELECT (data -> 'stop') ->> 'tz' FROM t"); + run_test("SELECT (ts AT TIME ZONE (tz || 'x'))::date FROM t"); run_test( "SELECT ((summary ->> 'ts')::timestamptz AT TIME ZONE ((summary -> 'stop') ->> 'tz'))::date AS d FROM s", );