diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index 8aa242651..202183786 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -79,15 +79,6 @@ jobs:
   lint:
     name: Lint Project
     runs-on: ubuntu-latest
-    services:
-      postgres:
-        image: postgres:latest
-        env:
-          POSTGRES_USER: postgres
-          POSTGRES_PASSWORD: postgres
-          POSTGRES_DB: postgres
-        ports:
-          - 5432:5432
     steps:
       - name: Checkout PR Branch
         uses: actions/checkout@v4
@@ -103,6 +94,24 @@ jobs:
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
+      # we need to use the same database as we do locally for sqlx prepare to output the same hashes
+      - name: Build and start PostgreSQL with plpgsql_check
+        run: |
+          docker build -t postgres-plpgsql-check:latest .
+          docker run -d --name postgres \
+            -e POSTGRES_USER=postgres \
+            -e POSTGRES_PASSWORD=postgres \
+            -e POSTGRES_DB=postgres \
+            -p 5432:5432 \
+            postgres-plpgsql-check:latest
+          # Wait for postgres to be ready
+          for _ in {1..30}; do
+            if docker exec postgres pg_isready -U postgres; then
+              break
+            fi
+            sleep 1
+          done
+
       - name: Setup sqlx-cli
         run: cargo install sqlx-cli
 
@@ -154,13 +163,37 @@ jobs:
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
 
-      # running containers via `services` only works on linux
-      # https://github.com/actions/runner/issues/1866
-      - name: Setup postgres
+      # For Linux, use custom Docker image with plpgsql_check
+      - name: Build and start PostgreSQL with plpgsql_check
+        if: runner.os == 'Linux'
+        run: |
+          docker build -t postgres-plpgsql-check:latest .
+          docker run -d --name postgres \
+            -e POSTGRES_USER=postgres \
+            -e POSTGRES_PASSWORD=postgres \
+            -e POSTGRES_DB=postgres \
+            -p 5432:5432 \
+            postgres-plpgsql-check:latest
+          # Wait for postgres to be ready
+          for _ in {1..30}; do
+            if docker exec postgres pg_isready -U postgres; then
+              break
+            fi
+            sleep 1
+          done
+      # For Windows, use the action since PostgreSQL Docker image doesn't support Windows containers
+      - name: Setup postgres (Windows)
+        if: runner.os == 'Windows'
         id: postgres
         uses: ikalnytskyi/action-setup-postgres@v7
       - name: Print Roles
-        run: psql ${{ steps.postgres.outputs.connection-uri }} -c "select rolname from pg_roles;"
+        run: |
+          if [[ "$RUNNER_OS" == "Linux" ]]; then
+            docker exec postgres psql -U postgres -c "select rolname from pg_roles;"
+          else
+            psql ${{ steps.postgres.outputs.connection-uri }} -c "select rolname from pg_roles;"
+          fi
+        shell: bash
       - name: Run tests
         run: cargo test --workspace
 
diff --git a/.gitmodules b/.gitmodules
index 4b56d7486..9b62ce889 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,7 +1,3 @@
-[submodule "libpg_query"]
-	path = libpg_query
-	url = https://github.com/pganalyze/libpg_query.git
-    branch = 17-latest
 [submodule "crates/tree_sitter_sql/tree-sitter-sql"]
 	path = lib/tree_sitter_sql/tree-sitter-sql
 	url = https://github.com/DerekStride/tree-sitter-sql
diff --git a/.sqlx/query-277e47bf46f8331549f55c8a0ebae6f3075c4f754cd379b0555c205fff95a95c.json b/.sqlx/query-277e47bf46f8331549f55c8a0ebae6f3075c4f754cd379b0555c205fff95a95c.json
new file mode 100644
index 000000000..db3f4a735
--- /dev/null
+++ b/.sqlx/query-277e47bf46f8331549f55c8a0ebae6f3075c4f754cd379b0555c205fff95a95c.json
@@ -0,0 +1,50 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "-- we need to join tables from the pg_catalog since \"TRUNCATE\" triggers are\n-- not available in the information_schema.trigger table.\nselect\n t.tgname as \"name!\",\n c.relname as \"table_name!\",\n p.proname as \"proc_name!\",\n proc_ns.nspname as \"proc_schema!\",\n table_ns.nspname as \"table_schema!\",\n t.tgtype as \"details_bitmask!\"\nfrom\n pg_catalog.pg_trigger t\nleft join pg_catalog.pg_proc p on t.tgfoid = p.oid\nleft join pg_catalog.pg_class c on t.tgrelid = c.oid\nleft join pg_catalog.pg_namespace table_ns on c.relnamespace = table_ns.oid\nleft join pg_catalog.pg_namespace proc_ns on p.pronamespace = proc_ns.oid\nwhere\n t.tgisinternal = false and\n t.tgconstraint = 0;\n",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "name!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 1,
+        "name": "table_name!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 2,
+        "name": "proc_name!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 3,
+        "name": "proc_schema!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 4,
+        "name": "table_schema!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 5,
+        "name": "details_bitmask!",
+        "type_info": "Int2"
+      }
+    ],
+    "parameters": {
+      "Left": []
+    },
+    "nullable": [
+      false,
+      true,
+      true,
+      true,
+      true,
+      false
+    ]
+  },
+  "hash": "277e47bf46f8331549f55c8a0ebae6f3075c4f754cd379b0555c205fff95a95c"
+}
diff --git a/.sqlx/query-3ebf3d74eb9d0448d675882c7f8a23f1440c250590de976c5c46c5edf6746faf.json b/.sqlx/query-3ebf3d74eb9d0448d675882c7f8a23f1440c250590de976c5c46c5edf6746faf.json
new file mode 100644
index 000000000..1b9220621
--- /dev/null
+++ b/.sqlx/query-3ebf3d74eb9d0448d675882c7f8a23f1440c250590de976c5c46c5edf6746faf.json
@@ -0,0 +1,44 @@
+{
+  "db_name": "PostgreSQL",
+  "query": "SELECT\n  e.name as \"name!\",\n  n.nspname AS schema,\n  e.default_version as \"default_version!\",\n  x.extversion AS installed_version,\n  e.comment\nFROM\n  pg_available_extensions() e(name, default_version, comment)\n  LEFT JOIN pg_extension x ON e.name = x.extname\n  LEFT JOIN pg_namespace n ON x.extnamespace = n.oid\n",
+  "describe": {
+    "columns": [
+      {
+        "ordinal": 0,
+        "name": "name!",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 1,
+        "name": "schema",
+        "type_info": "Name"
+      },
+      {
+        "ordinal": 2,
+        "name": "default_version!",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 3,
+        "name": "installed_version",
+        "type_info": "Text"
+      },
+      {
+        "ordinal": 4,
+        "name": "comment",
+        "type_info": "Text"
+      }
+    ],
+    "parameters": {
+      "Left": []
+    },
+    "nullable": [
+      null,
+      true,
+      null,
+      true,
+      null
+    ]
+  },
+  "hash": "3ebf3d74eb9d0448d675882c7f8a23f1440c250590de976c5c46c5edf6746faf"
+}
diff --git a/.sqlx/query-4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502.json b/.sqlx/query-4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502.json
index 4980f4f37..400f031d9 100644
--- a/.sqlx/query-4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502.json
+++ b/.sqlx/query-4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502.json
@@ -90,9 +90,9 @@
     "nullable": [
       null,
       true,
+      false,
       true,
-      true,
-      true,
+      false,
       null,
       null,
       null,
@@ -101,9 +101,9 @@
       null,
       null,
       null,
-      true,
+      false,
       null,
-      true
+      false
     ]
   },
   "hash": "4ea19fee016f1daeafdc466647d117910b19f540f19393b76aa6434e9d1d8502"
diff --git a/.sqlx/query-df57cc22f7d63847abce1d0d15675ba8951faa1be2ea6b2bf6714b1aa9127a6f.json b/.sqlx/query-df57cc22f7d63847abce1d0d15675ba8951faa1be2ea6b2bf6714b1aa9127a6f.json
deleted file mode 100644
index b6fd2fc80..000000000
--- a/.sqlx/query-df57cc22f7d63847abce1d0d15675ba8951faa1be2ea6b2bf6714b1aa9127a6f.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "db_name": "PostgreSQL",
-  "query": "-- we need to join tables from the pg_catalog since \"TRUNCATE\" triggers are \n-- not available in the information_schema.trigger table.\nselect \n  t.tgname as \"name!\",\n  c.relname as \"table_name!\",\n  p.proname as \"proc_name!\",\n  n.nspname as \"schema_name!\",\n  t.tgtype as \"details_bitmask!\"\nfrom \n  pg_catalog.pg_trigger t \n  left join pg_catalog.pg_proc p on t.tgfoid = p.oid\n  left join pg_catalog.pg_class c on t.tgrelid = c.oid\n  left join pg_catalog.pg_namespace n on c.relnamespace = n.oid\nwhere \n  -- triggers enforcing constraints (e.g. unique fields) should not be included.\n  t.tgisinternal = false and \n  t.tgconstraint = 0;\n",
-  "describe": {
-    "columns": [
-      {
-        "ordinal": 0,
-        "name": "name!",
-        "type_info": "Name"
-      },
-      {
-        "ordinal": 1,
-        "name": "table_name!",
-        "type_info": "Name"
-      },
-      {
-        "ordinal": 2,
-        "name": "proc_name!",
-        "type_info": "Name"
-      },
-      {
-        "ordinal": 3,
-        "name": "schema_name!",
-        "type_info": "Name"
-      },
-      {
-        "ordinal": 4,
-        "name": "details_bitmask!",
-        "type_info": "Int2"
-      }
-    ],
-    "parameters": {
-      "Left": []
-    },
-    "nullable": [
-      false,
-      true,
-      true,
-      true,
-      false
-    ]
-  },
-  "hash": "df57cc22f7d63847abce1d0d15675ba8951faa1be2ea6b2bf6714b1aa9127a6f"
-}
diff --git a/Cargo.lock b/Cargo.lock
index 16b1de5e6..49143908b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -24,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
 dependencies = [
  "cfg-if",
- "getrandom",
+ "getrandom 0.2.15",
  "once_cell",
  "version_check",
  "zerocopy",
@@ -106,6 +106,18 @@ version = "1.0.94"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
 
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
 [[package]]
 name = "assert_cmd"
 version = "2.0.16"
@@ -333,6 +345,12 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "base64"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+
 [[package]]
 name = "base64"
 version = "0.22.1"
@@ -353,25 +371,22 @@ checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
 
 [[package]]
 name = "bindgen"
-version = "0.66.1"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
+checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f"
 dependencies = [
  "bitflags 2.6.0",
  "cexpr",
  "clang-sys",
- "lazy_static",
- "lazycell",
+ "itertools 0.10.5",
  "log",
- "peeking_take_while",
  "prettyplease",
  "proc-macro2",
  "quote",
  "regex",
- "rustc-hash 1.1.0",
+ "rustc-hash 2.1.0",
  "shlex",
  "syn 2.0.90",
- "which",
 ]
 
 [[package]]
@@ -683,6 +698,17 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "blake2b_simd"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "constant_time_eq",
+]
+
 [[package]]
 name = "block-buffer"
 version = "0.10.4"
@@ -884,6 +910,15 @@ version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
 
+[[package]]
+name = "clippy"
+version = "0.0.302"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d911ee15579a3f50880d8c1d59ef6e79f9533127a3bd342462f5d584f5e8c294"
+dependencies = [
+ "term",
+]
+
 [[package]]
 name = "colorchoice"
 version = "1.0.3"
@@ -917,6 +952,12 @@ version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
 
+[[package]]
+name = "constant_time_eq"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
 [[package]]
 name = "convert_case"
 version = "0.6.0"
@@ -1204,6 +1245,17 @@ dependencies = [
  "dirs-sys",
 ]
 
+[[package]]
+name = "dirs"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
+dependencies = [
+ "libc",
+ "redox_users 0.3.5",
+ "winapi",
+]
+
 [[package]]
 name = "dirs-sys"
 version = "0.4.1"
@@ -1212,7 +1264,7 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
 dependencies = [
  "libc",
  "option-ext",
- "redox_users",
+ "redox_users 0.4.6",
  "windows-sys 0.48.0",
 ]
 
@@ -1247,6 +1299,7 @@ dependencies = [
  "pgt_console",
  "pgt_diagnostics",
  "pgt_flags",
+ "pgt_query",
  "pgt_query_ext",
  "pgt_statement_splitter",
  "pgt_workspace",
@@ -1287,6 +1340,12 @@ version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
 
+[[package]]
+name = "easy-parallel"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2afbb9b0aef60e4f0d2b18129b6c0dff035a6f7dbbd17c2f38c1432102ee223c"
+
 [[package]]
 name = "either"
 version = "1.13.0"
@@ -1641,6 +1700,17 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.15"
@@ -1649,7 +1719,7 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
 ]
 
 [[package]]
@@ -2128,12 +2198,6 @@ dependencies = [
  "spin",
 ]
 
-[[package]]
-name = "lazycell"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
-
 [[package]]
 name = "libc"
 version = "0.2.168"
@@ -2373,7 +2437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
 dependencies = [
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
  "windows-sys 0.52.0",
 ]
 
@@ -2605,7 +2669,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.5.7",
  "smallvec",
  "windows-targets 0.52.6",
 ]
@@ -2634,12 +2698,6 @@ dependencies = [
  "once_cell",
 ]
 
-[[package]]
-name = "peeking_take_while"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
-
 [[package]]
 name = "pem-rfc7468"
 version = "0.7.0"
@@ -2665,24 +2723,6 @@ dependencies = [
  "indexmap 2.7.0",
 ]
 
-[[package]]
-name = "pg_query"
-version = "6.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f71c7c56dfe299ec6f98aa210aa23458be3b0610c485be60a5873c2f3627c40e"
-dependencies = [
- "bindgen",
- "cc",
- "fs_extra",
- "glob",
- "itertools 0.10.5",
- "prost",
- "prost-build",
- "serde",
- "serde_json",
- "thiserror 1.0.69",
-]
-
 [[package]]
 name = "pgt_analyse"
 version = "0.0.0"
@@ -2692,7 +2732,7 @@ dependencies = [
  "enumflags2",
  "pgt_console",
  "pgt_diagnostics",
- "pgt_query_ext",
+ "pgt_query",
  "pgt_schema_cache",
  "pgt_text_size",
  "rustc-hash 2.1.0",
@@ -2708,7 +2748,7 @@ dependencies = [
  "pgt_analyse",
  "pgt_console",
  "pgt_diagnostics",
- "pgt_query_ext",
+ "pgt_query",
  "pgt_schema_cache",
  "pgt_test_macros",
  "pgt_text_size",
@@ -2765,7 +2805,7 @@ dependencies = [
  "pgt_schema_cache",
  "pgt_test_utils",
  "pgt_text_size",
- "pgt_treesitter_queries",
+ "pgt_treesitter",
  "schemars",
  "serde",
  "serde_json",
@@ -2936,23 +2976,60 @@ dependencies = [
  "quote",
 ]
 
+[[package]]
+name = "pgt_plpgsql_check"
+version = "0.0.0"
+dependencies = [
+ "pgt_console",
+ "pgt_diagnostics",
+ "pgt_query",
+ "pgt_query_ext",
+ "pgt_schema_cache",
+ "pgt_test_utils",
+ "pgt_text_size",
+ "regex",
+ "serde",
+ "serde_json",
+ "sqlx",
+ "tree-sitter",
+]
+
+[[package]]
+name = "pgt_query"
+version = "0.0.0"
+dependencies = [
+ "bindgen",
+ "cc",
+ "clippy",
+ "easy-parallel",
+ "fs_extra",
+ "glob",
+ "pgt_query_macros",
+ "prost",
+ "prost-build",
+ "thiserror 1.0.69",
+ "which",
+]
+
 [[package]]
 name = "pgt_query_ext"
 version = "0.0.0"
 dependencies = [
- "petgraph",
- "pg_query",
  "pgt_diagnostics",
+ "pgt_query",
  "pgt_text_size",
 ]
 
 [[package]]
-name = "pgt_query_proto_parser"
+name = "pgt_query_macros"
 version = "0.0.0"
 dependencies = [
  "convert_case",
- "protobuf",
- "protobuf-parse",
+ "proc-macro2",
+ "prost-reflect",
+ "protox",
+ "quote",
+ "ureq",
 ]
 
 [[package]]
@@ -2980,7 +3057,7 @@ dependencies = [
  "ntest",
  "pgt_diagnostics",
  "pgt_lexer",
- "pgt_query_ext",
+ "pgt_query",
  "pgt_text_size",
  "regex",
 ]
@@ -3047,10 +3124,13 @@ dependencies = [
 ]
 
 [[package]]
-name = "pgt_treesitter_queries"
+name = "pgt_treesitter"
 version = "0.0.0"
 dependencies = [
  "clap 4.5.23",
+ "pgt_schema_cache",
+ "pgt_test_utils",
+ "pgt_text_size",
  "tree-sitter",
  "tree_sitter_sql",
 ]
@@ -3059,7 +3139,7 @@ dependencies = [
 name = "pgt_type_resolver"
 version = "0.0.0"
 dependencies = [
- "pgt_query_ext",
+ "pgt_query",
  "pgt_schema_cache",
 ]
 
@@ -3070,11 +3150,11 @@ dependencies = [
  "insta",
  "pgt_console",
  "pgt_diagnostics",
- "pgt_query_ext",
+ "pgt_query",
  "pgt_schema_cache",
  "pgt_test_utils",
  "pgt_text_size",
- "pgt_treesitter_queries",
+ "pgt_treesitter",
  "sqlx",
  "tokio",
  "tree-sitter",
@@ -3101,6 +3181,8 @@ dependencies = [
  "pgt_diagnostics",
  "pgt_fs",
  "pgt_lexer",
+ "pgt_plpgsql_check",
+ "pgt_query",
  "pgt_query_ext",
  "pgt_schema_cache",
  "pgt_statement_splitter",
@@ -3108,6 +3190,7 @@ dependencies = [
  "pgt_test_utils",
  "pgt_text_size",
  "pgt_typecheck",
+ "pgt_workspace_macros",
  "rustc-hash 2.1.0",
  "schemars",
  "serde",
@@ -3122,6 +3205,15 @@ dependencies = [
  "tree_sitter_sql",
 ]
 
+[[package]]
+name = "pgt_workspace_macros"
+version = "0.0.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "pin-project"
 version = "1.1.7"
@@ -3341,9 +3433,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.93"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
 dependencies = [
  "unicode-ident",
 ]
@@ -3412,42 +3504,6 @@ dependencies = [
  "prost",
 ]
 
-[[package]]
-name = "protobuf"
-version = "3.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3a7c64d9bf75b1b8d981124c14c179074e8caa7dfe7b6a12e6222ddcd0c8f72"
-dependencies = [
- "once_cell",
- "protobuf-support",
- "thiserror 1.0.69",
-]
-
-[[package]]
-name = "protobuf-parse"
-version = "3.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322330e133eab455718444b4e033ebfac7c6528972c784fcde28d2cc783c6257"
-dependencies = [
- "anyhow",
- "indexmap 2.7.0",
- "log",
- "protobuf",
- "protobuf-support",
- "tempfile",
- "thiserror 1.0.69",
- "which",
-]
-
-[[package]]
-name = "protobuf-support"
-version = "3.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b088fd20b938a875ea00843b6faf48579462630015c3788d397ad6a786663252"
-dependencies = [
- "thiserror 1.0.69",
-]
-
 [[package]]
 name = "protox"
 version = "0.8.0"
@@ -3554,7 +3610,7 @@ version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
 ]
 
 [[package]]
@@ -3577,6 +3633,12 @@ dependencies = [
  "crossbeam-utils",
 ]
 
+[[package]]
+name = "redox_syscall"
+version = "0.1.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
+
 [[package]]
 name = "redox_syscall"
 version = "0.5.7"
@@ -3586,13 +3648,24 @@ dependencies = [
  "bitflags 2.6.0",
 ]
 
+[[package]]
+name = "redox_users"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
+dependencies = [
+ "getrandom 0.1.16",
+ "redox_syscall 0.1.57",
+ "rust-argon2",
+]
+
 [[package]]
 name = "redox_users"
 version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
  "libredox",
  "thiserror 1.0.69",
 ]
@@ -3649,7 +3722,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
 dependencies = [
  "cc",
  "cfg-if",
- "getrandom",
+ "getrandom 0.2.15",
  "libc",
  "untrusted",
  "windows-sys 0.52.0",
@@ -3684,12 +3757,25 @@ dependencies = [
  "pgt_analyser",
  "pgt_console",
  "pgt_diagnostics",
+ "pgt_query",
  "pgt_query_ext",
  "pgt_statement_splitter",
  "pgt_workspace",
  "pulldown-cmark",
 ]
 
+[[package]]
+name = "rust-argon2"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
+dependencies = [
+ "base64 0.13.1",
+ "blake2b_simd",
+ "constant_time_eq",
+ "crossbeam-utils",
+]
+
 [[package]]
 name = "rustc-demangle"
 version = "0.1.24"
@@ -4184,7 +4270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a"
 dependencies = [
  "atoi",
- "base64",
+ "base64 0.22.1",
  "bitflags 2.6.0",
  "byteorder",
  "bytes",
@@ -4226,7 +4312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8"
 dependencies = [
  "atoi",
- "base64",
+ "base64 0.22.1",
  "bitflags 2.6.0",
  "byteorder",
  "crc",
@@ -4402,12 +4488,23 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
 dependencies = [
  "cfg-if",
  "fastrand 2.3.0",
- "getrandom",
+ "getrandom 0.2.15",
  "once_cell",
  "rustix 0.38.42",
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "term"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
+dependencies = [
+ "byteorder",
+ "dirs",
+ "winapi",
+]
+
 [[package]]
 name = "termcolor"
 version = "1.4.1"
@@ -4978,7 +5075,7 @@ version = "2.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
 dependencies = [
- "base64",
+ "base64 0.22.1",
  "flate2",
  "log",
  "once_cell",
@@ -5024,7 +5121,7 @@ version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.15",
 ]
 
 [[package]]
@@ -5096,6 +5193,12 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -5205,14 +5308,14 @@ dependencies = [
 
 [[package]]
 name = "which"
-version = "4.4.2"
+version = "6.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
 dependencies = [
  "either",
  "home",
- "once_cell",
  "rustix 0.38.42",
+ "winsafe",
 ]
 
 [[package]]
@@ -5221,7 +5324,7 @@ version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d"
 dependencies = [
- "redox_syscall",
+ "redox_syscall 0.5.7",
  "wasite",
 ]
 
@@ -5413,6 +5516,12 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "winsafe"
+version = "0.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
+
 [[package]]
 name = "write-json"
 version = "0.1.4"
diff --git a/Cargo.toml b/Cargo.toml
index 15c6f02ff..d68aafe04 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,12 +44,14 @@ smallvec                 = { version = "1.13.2", features = ["union", "const_new
 strum                    = { version = "0.27.1", features = ["derive"] }
 # this will use tokio if available, otherwise async-std
 convert_case             = "0.6.0"
+prost                    = "0.13.5"
 prost-reflect            = "0.15.3"
 protox                   = "0.8.0"
 sqlx                     = { version = "0.8.2", features = ["runtime-tokio", "runtime-async-std", "postgres", "json"] }
-syn                      = "1.0.109"
+syn                      = { version = "1.0.109", features = ["full"] }
 termcolor                = "1.4.1"
 test-log                 = "0.2.17"
+thiserror                = "1.0.31"
 tokio                    = { version = "1.40.0", features = ["full"] }
 tracing                  = { version = "0.1.40", default-features = false, features = ["std"] }
 tracing-bunyan-formatter = { version = "0.3.10 " }
@@ -74,17 +76,20 @@ pgt_lexer                  = { path = "./crates/pgt_lexer", version = "0.0.0" }
 pgt_lexer_codegen          = { path = "./crates/pgt_lexer_codegen", version = "0.0.0" }
 pgt_lsp                    = { path = "./crates/pgt_lsp", version = "0.0.0" }
 pgt_markup                 = { path = "./crates/pgt_markup", version = "0.0.0" }
+pgt_plpgsql_check          = { path = "./crates/pgt_plpgsql_check", version = "0.0.0" }
+pgt_query                  = { path = "./crates/pgt_query", version = "0.0.0" }
 pgt_query_ext              = { path = "./crates/pgt_query_ext", version = "0.0.0" }
-pgt_query_proto_parser     = { path = "./crates/pgt_query_proto_parser", version = "0.0.0" }
+pgt_query_macros           = { path = "./crates/pgt_query_macros", version = "0.0.0" }
 pgt_schema_cache           = { path = "./crates/pgt_schema_cache", version = "0.0.0" }
 pgt_statement_splitter     = { path = "./crates/pgt_statement_splitter", version = "0.0.0" }
 pgt_suppressions           = { path = "./crates/pgt_suppressions", version = "0.0.0" }
 pgt_text_edit              = { path = "./crates/pgt_text_edit", version = "0.0.0" }
 pgt_text_size              = { path = "./crates/pgt_text_size", version = "0.0.0" }
 pgt_tokenizer              = { path = "./crates/pgt_tokenizer", version = "0.0.0" }
-pgt_treesitter_queries     = { path = "./crates/pgt_treesitter_queries", version = "0.0.0" }
+pgt_treesitter             = { path = "./crates/pgt_treesitter", version = "0.0.0" }
 pgt_typecheck              = { path = "./crates/pgt_typecheck", version = "0.0.0" }
 pgt_workspace              = { path = "./crates/pgt_workspace", version = "0.0.0" }
+pgt_workspace_macros       = { path = "./crates/pgt_workspace_macros", version = "0.0.0" }
 
 pgt_test_macros = { path = "./crates/pgt_test_macros" }
 pgt_test_utils  = { path = "./crates/pgt_test_utils" }
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 000000000..10353bb27
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,16 @@
+FROM postgres:15
+
+# Install build dependencies
+RUN apt-get update && \
+    apt-get install -y postgresql-server-dev-15 gcc make git && \
+    cd /tmp && \
+    git clone https://github.com/okbob/plpgsql_check.git && \
+    cd plpgsql_check && \
+    make && \
+    make install && \
+    apt-get remove -y postgresql-server-dev-15 gcc make git && \
+    apt-get autoremove -y && \
+    rm -rf /tmp/plpgsql_check /var/lib/apt/lists/*
+
+# Add initialization script directly
+RUN echo "CREATE EXTENSION IF NOT EXISTS plpgsql_check;" > /docker-entrypoint-initdb.d/01-create-extension.sql
\ No newline at end of file
diff --git a/crates/pgt_analyse/Cargo.toml b/crates/pgt_analyse/Cargo.toml
index 4d30784c8..3da600343 100644
--- a/crates/pgt_analyse/Cargo.toml
+++ b/crates/pgt_analyse/Cargo.toml
@@ -15,7 +15,7 @@ version              = "0.0.0"
 [dependencies]
 pgt_console.workspace      = true
 pgt_diagnostics.workspace  = true
-pgt_query_ext.workspace    = true
+pgt_query.workspace        = true
 pgt_schema_cache.workspace = true
 rustc-hash                 = { workspace = true }
 
diff --git a/crates/pgt_analyse/src/analysed_file_context.rs b/crates/pgt_analyse/src/analysed_file_context.rs
index cba53eebe..82dc40711 100644
--- a/crates/pgt_analyse/src/analysed_file_context.rs
+++ b/crates/pgt_analyse/src/analysed_file_context.rs
@@ -3,5 +3,5 @@ pub struct AnalysedFileContext {}
 
 impl AnalysedFileContext {
     #[allow(unused)]
-    pub fn update_from(&mut self, stmt_root: &pgt_query_ext::NodeEnum) {}
+    pub fn update_from(&mut self, stmt_root: &pgt_query::NodeEnum) {}
 }
diff --git a/crates/pgt_analyse/src/context.rs b/crates/pgt_analyse/src/context.rs
index 7447c0bb5..ddd5d28d5 100644
--- a/crates/pgt_analyse/src/context.rs
+++ b/crates/pgt_analyse/src/context.rs
@@ -7,7 +7,7 @@ use crate::{
 };
 
 pub struct RuleContext<'a, R: Rule> {
-    stmt: &'a pgt_query_ext::NodeEnum,
+    stmt: &'a pgt_query::NodeEnum,
     options: &'a R::Options,
     schema_cache: Option<&'a SchemaCache>,
     file_context: &'a AnalysedFileContext,
@@ -19,7 +19,7 @@ where
 {
     #[allow(clippy::too_many_arguments)]
     pub fn new(
-        stmt: &'a pgt_query_ext::NodeEnum,
+        stmt: &'a pgt_query::NodeEnum,
         options: &'a R::Options,
         schema_cache: Option<&'a SchemaCache>,
         file_context: &'a AnalysedFileContext,
@@ -43,7 +43,7 @@ where
     }
 
     /// Returns the AST root
-    pub fn stmt(&self) -> &pgt_query_ext::NodeEnum {
+    pub fn stmt(&self) -> &pgt_query::NodeEnum {
         self.stmt
     }
 
diff --git a/crates/pgt_analyse/src/registry.rs b/crates/pgt_analyse/src/registry.rs
index d43d77115..45d2c2026 100644
--- a/crates/pgt_analyse/src/registry.rs
+++ b/crates/pgt_analyse/src/registry.rs
@@ -157,7 +157,7 @@ impl RuleRegistry {
 }
 
 pub struct RegistryRuleParams<'a> {
-    pub root: &'a pgt_query_ext::NodeEnum,
+    pub root: &'a pgt_query::NodeEnum,
     pub options: &'a AnalyserOptions,
     pub analysed_file_context: &'a AnalysedFileContext,
     pub schema_cache: Option<&'a pgt_schema_cache::SchemaCache>,
diff --git a/crates/pgt_analyser/Cargo.toml b/crates/pgt_analyser/Cargo.toml
index 5f65b9787..0cf7a3342 100644
--- a/crates/pgt_analyser/Cargo.toml
+++ b/crates/pgt_analyser/Cargo.toml
@@ -15,7 +15,7 @@ version              = "0.0.0"
 pgt_analyse      = { workspace = true }
 pgt_console      = { workspace = true }
 pgt_diagnostics  = { workspace = true }
-pgt_query_ext    = { workspace = true }
+pgt_query        = { workspace = true }
 pgt_schema_cache = { workspace = true }
 pgt_text_size    = { workspace = true }
 serde            = { workspace = true }
diff --git a/crates/pgt_analyser/src/lib.rs b/crates/pgt_analyser/src/lib.rs
index f96b6f6df..ccdc04208 100644
--- a/crates/pgt_analyser/src/lib.rs
+++ b/crates/pgt_analyser/src/lib.rs
@@ -32,7 +32,7 @@ pub struct Analyser<'a> {
 
 #[derive(Debug)]
 pub struct AnalysableStatement {
-    pub root: pgt_query_ext::NodeEnum,
+    pub root: pgt_query::NodeEnum,
     pub range: pgt_text_size::TextRange,
 }
 
@@ -123,7 +123,7 @@ mod tests {
             ..Default::default()
         };
 
-        let ast = pgt_query_ext::parse(SQL).expect("failed to parse SQL");
+        let ast = pgt_query::parse(SQL).expect("failed to parse SQL");
         let range = TextRange::new(0.into(), u32::try_from(SQL.len()).unwrap().into());
 
         let options = AnalyserOptions::default();
@@ -134,7 +134,10 @@ mod tests {
         });
 
         let results = analyser.run(crate::AnalyserParams {
-            stmts: vec![AnalysableStatement { root: ast, range }],
+            stmts: vec![AnalysableStatement {
+                root: ast.into_root().unwrap(),
+                range,
+            }],
             schema_cache: None,
         });
 
diff --git a/crates/pgt_analyser/src/lint/safety/adding_required_field.rs b/crates/pgt_analyser/src/lint/safety/adding_required_field.rs
index 069019528..d853d30a2 100644
--- a/crates/pgt_analyser/src/lint/safety/adding_required_field.rs
+++ b/crates/pgt_analyser/src/lint/safety/adding_required_field.rs
@@ -30,7 +30,7 @@ impl Rule for AddingRequiredField {
     fn run(ctx: &RuleContext<Self>) -> Vec<RuleDiagnostic> {
         let mut diagnostics = vec![];
 
-        if let pgt_query_ext::NodeEnum::AlterTableStmt(stmt) = ctx.stmt() {
+        if let pgt_query::NodeEnum::AlterTableStmt(stmt) = ctx.stmt() {
             // We are currently lacking a way to check if a `AtAddColumn` subtype sets a
             // not null constraint – so we'll need to check the plain SQL.
             let plain_sql = ctx.stmt().to_ref().deparse().unwrap().to_ascii_lowercase();
@@ -41,9 +41,8 @@ impl Rule for AddingRequiredField {
             }
 
             for cmd in &stmt.cmds {
-                if let Some(pgt_query_ext::NodeEnum::AlterTableCmd(alter_table_cmd)) = &cmd.node {
-                    if alter_table_cmd.subtype()
-                        == pgt_query_ext::protobuf::AlterTableType::AtAddColumn
+                if let Some(pgt_query::NodeEnum::AlterTableCmd(alter_table_cmd)) = &cmd.node {
+                    if alter_table_cmd.subtype() == pgt_query::protobuf::AlterTableType::AtAddColumn
                     {
                         diagnostics.push(
                             RuleDiagnostic::new(
diff --git a/crates/pgt_analyser/src/lint/safety/ban_drop_column.rs b/crates/pgt_analyser/src/lint/safety/ban_drop_column.rs
index 165d4230f..d73b39d24 100644
--- a/crates/pgt_analyser/src/lint/safety/ban_drop_column.rs
+++ b/crates/pgt_analyser/src/lint/safety/ban_drop_column.rs
@@ -32,10 +32,10 @@ impl Rule for BanDropColumn {
     fn run(ctx: &RuleContext<Self>) -> Vec<RuleDiagnostic> {
         let mut diagnostics = Vec::new();
 
-        if let pgt_query_ext::NodeEnum::AlterTableStmt(stmt) = &ctx.stmt() {
+        if let pgt_query::NodeEnum::AlterTableStmt(stmt) = &ctx.stmt() {
             for cmd in &stmt.cmds {
-                if let Some(pgt_query_ext::NodeEnum::AlterTableCmd(cmd)) = &cmd.node {
-                    if cmd.subtype() == pgt_query_ext::protobuf::AlterTableType::AtDropColumn {
+                if let Some(pgt_query::NodeEnum::AlterTableCmd(cmd)) = &cmd.node {
+                    if cmd.subtype() == pgt_query::protobuf::AlterTableType::AtDropColumn {
                         diagnostics.push(RuleDiagnostic::new(
                             rule_category!(),
                             None,
diff --git a/crates/pgt_analyser/src/lint/safety/ban_drop_database.rs b/crates/pgt_analyser/src/lint/safety/ban_drop_database.rs
index 11d07da9a..3011cf88d 100644
--- a/crates/pgt_analyser/src/lint/safety/ban_drop_database.rs
+++ b/crates/pgt_analyser/src/lint/safety/ban_drop_database.rs
@@ -21,7 +21,7 @@ impl Rule for BanDropDatabase {
     fn run(ctx: &RuleContext<Self>) -> Vec<RuleDiagnostic> {
         let mut diagnostics = vec![];
 
-        if let pgt_query_ext::NodeEnum::DropdbStmt(_) = &ctx.stmt() {
+        if let pgt_query::NodeEnum::DropdbStmt(_) = &ctx.stmt() {
             diagnostics.push(
                 RuleDiagnostic::new(
                     rule_category!(),
diff --git a/crates/pgt_analyser/src/lint/safety/ban_drop_not_null.rs b/crates/pgt_analyser/src/lint/safety/ban_drop_not_null.rs
index fa4c90115..c1e694618 100644
--- a/crates/pgt_analyser/src/lint/safety/ban_drop_not_null.rs
+++ b/crates/pgt_analyser/src/lint/safety/ban_drop_not_null.rs
@@ -32,10 +32,10 @@ impl Rule for BanDropNotNull {
     fn run(ctx: &RuleContext<Self>) -> Vec<RuleDiagnostic> {
         let mut diagnostics = Vec::new();
 
-        if let pgt_query_ext::NodeEnum::AlterTableStmt(stmt) = &ctx.stmt() {
+        if let pgt_query::NodeEnum::AlterTableStmt(stmt) = &ctx.stmt() {
             for cmd in &stmt.cmds {
-                if let Some(pgt_query_ext::NodeEnum::AlterTableCmd(cmd)) = &cmd.node {
-                    if cmd.subtype() == pgt_query_ext::protobuf::AlterTableType::AtDropNotNull {
+                if let Some(pgt_query::NodeEnum::AlterTableCmd(cmd)) = &cmd.node {
+                    if cmd.subtype() == pgt_query::protobuf::AlterTableType::AtDropNotNull {
                         diagnostics.push(RuleDiagnostic::new(
                             rule_category!(),
                             None,
diff --git a/crates/pgt_analyser/src/lint/safety/ban_drop_table.rs b/crates/pgt_analyser/src/lint/safety/ban_drop_table.rs
index 90c08514f..bcf784533 100644
--- a/crates/pgt_analyser/src/lint/safety/ban_drop_table.rs
+++ b/crates/pgt_analyser/src/lint/safety/ban_drop_table.rs
@@ -31,8 +31,8 @@ impl Rule for BanDropTable {
     fn run(ctx: &RuleContext<Self>) -> Vec<RuleDiagnostic> {
         let mut diagnostics = vec![];
 
-        if let pgt_query_ext::NodeEnum::DropStmt(stmt) = &ctx.stmt() {
-            if stmt.remove_type() == pgt_query_ext::protobuf::ObjectType::ObjectTable {
+        if let pgt_query::NodeEnum::DropStmt(stmt) = &ctx.stmt() {
+            if stmt.remove_type() == pgt_query::protobuf::ObjectType::ObjectTable {
                 diagnostics.push(
                     RuleDiagnostic::new(
                         rule_category!(),
diff --git a/crates/pgt_analyser/src/lint/safety/ban_truncate_cascade.rs b/crates/pgt_analyser/src/lint/safety/ban_truncate_cascade.rs
index cef5cd47b..1bc42d49b 100644
--- a/crates/pgt_analyser/src/lint/safety/ban_truncate_cascade.rs
+++ b/crates/pgt_analyser/src/lint/safety/ban_truncate_cascade.rs
@@ -1,7 +1,7 @@
 use pgt_analyse::{Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule};
 use pgt_console::markup;
 use pgt_diagnostics::Severity;
-use pgt_query_ext::protobuf::DropBehavior;
+use pgt_query::protobuf::DropBehavior;
 
 declare_lint_rule! {
     /// Using `TRUNCATE`'s `CASCADE` option will truncate any tables that are also foreign-keyed to the specified tables.
@@ -34,7 +34,7 @@ impl Rule for BanTruncateCascade {
     fn run(ctx: &RuleContext<Self>) -> Vec<RuleDiagnostic> {
         let mut diagnostics = Vec::new();
 
-        if let pgt_query_ext::NodeEnum::TruncateStmt(stmt) = &ctx.stmt() {
+        if let pgt_query::NodeEnum::TruncateStmt(stmt) = &ctx.stmt() {
             if stmt.behavior() == DropBehavior::DropCascade {
                 diagnostics.push(RuleDiagnostic::new(
                             rule_category!(),
diff --git a/crates/pgt_analyser/tests/rules_tests.rs b/crates/pgt_analyser/tests/rules_tests.rs
index 0a6b47ec5..d8e5b0ef1 100644
--- a/crates/pgt_analyser/tests/rules_tests.rs
+++ b/crates/pgt_analyser/tests/rules_tests.rs
@@ -25,7 +25,7 @@ fn rule_test(full_path: &'static str, _: &str, _: &str) {
     let query =
         read_to_string(full_path).unwrap_or_else(|_| panic!("Failed to read file: {} ", full_path));
 
-    let ast = pgt_query_ext::parse(&query).expect("failed to parse SQL");
+    let ast = pgt_query::parse(&query).expect("failed to parse SQL");
     let options = AnalyserOptions::default();
     let analyser = Analyser::new(AnalyserConfig {
         options: &options,
@@ -33,7 +33,7 @@ fn rule_test(full_path: &'static str, _: &str, _: &str) {
     });
 
     let stmt = AnalysableStatement {
-        root: ast,
+        root: ast.into_root().expect("Failed to convert AST to root node"),
         range: pgt_text_size::TextRange::new(0.into(), u32::try_from(query.len()).unwrap().into()),
     };
 
diff --git a/crates/pgt_completions/Cargo.toml b/crates/pgt_completions/Cargo.toml
index 916a00209..0ebb8e56e 100644
--- a/crates/pgt_completions/Cargo.toml
+++ b/crates/pgt_completions/Cargo.toml
@@ -14,18 +14,17 @@ version              = "0.0.0"
 [dependencies]
 async-std = "1.12.0"
 
-pgt_text_size.workspace = true
-
-
-fuzzy-matcher                    = "0.3.7"
-pgt_schema_cache.workspace       = true
-pgt_treesitter_queries.workspace = true
-schemars                         = { workspace = true, optional = true }
-serde                            = { workspace = true, features = ["derive"] }
-serde_json                       = { workspace = true }
-tracing                          = { workspace = true }
-tree-sitter.workspace            = true
-tree_sitter_sql.workspace        = true
+pgt_schema_cache.workspace = true
+pgt_text_size.workspace    = true
+pgt_treesitter.workspace   = true
+
+fuzzy-matcher             = "0.3.7"
+schemars                  = { workspace = true, optional = true }
+serde                     = { workspace = true, features = ["derive"] }
+serde_json                = { workspace = true }
+tracing                   = { workspace = true }
+tree-sitter.workspace     = true
+tree_sitter_sql.workspace = true
 
 sqlx.workspace = true
 
diff --git a/crates/pgt_completions/src/builder.rs b/crates/pgt_completions/src/builder.rs
index 96576053f..bf8eb66a6 100644
--- a/crates/pgt_completions/src/builder.rs
+++ b/crates/pgt_completions/src/builder.rs
@@ -1,10 +1,11 @@
 use crate::{
     CompletionItemKind, CompletionText,
-    context::CompletionContext,
     item::CompletionItem,
     relevance::{filtering::CompletionFilter, scoring::CompletionScore},
 };
 
+use pgt_treesitter::TreesitterContext;
+
 pub(crate) struct PossibleCompletionItem<'a> {
     pub label: String,
     pub description: String,
@@ -17,11 +18,11 @@ pub(crate) struct PossibleCompletionItem<'a> {
 
 pub(crate) struct CompletionBuilder<'a> {
     items: Vec<PossibleCompletionItem<'a>>,
-    ctx: &'a CompletionContext<'a>,
+    ctx: &'a TreesitterContext<'a>,
 }
 
 impl<'a> CompletionBuilder<'a> {
-    pub fn new(ctx: &'a CompletionContext) -> Self {
+    pub fn new(ctx: &'a TreesitterContext) -> Self {
         CompletionBuilder { items: vec![], ctx }
     }
 
diff --git a/crates/pgt_completions/src/complete.rs b/crates/pgt_completions/src/complete.rs
index bd5efd19d..e18589af0 100644
--- a/crates/pgt_completions/src/complete.rs
+++ b/crates/pgt_completions/src/complete.rs
@@ -1,8 +1,9 @@
 use pgt_text_size::TextSize;
 
+use pgt_treesitter::{TreeSitterContextParams, context::TreesitterContext};
+
 use crate::{
     builder::CompletionBuilder,
-    context::CompletionContext,
     item::CompletionItem,
     providers::{
         complete_columns, complete_functions, complete_policies, complete_roles, complete_schemas,
@@ -28,16 +29,20 @@ pub struct CompletionParams<'a> {
 pub fn complete(params: CompletionParams) -> Vec<CompletionItem> {
     let sanitized_params = SanitizedCompletionParams::from(params);
 
-    let ctx = CompletionContext::new(&sanitized_params);
+    let ctx = TreesitterContext::new(TreeSitterContextParams {
+        position: sanitized_params.position,
+        text: &sanitized_params.text,
+        tree: &sanitized_params.tree,
+    });
 
     let mut builder = CompletionBuilder::new(&ctx);
 
-    complete_tables(&ctx, &mut builder);
-    complete_functions(&ctx, &mut builder);
-    complete_columns(&ctx, &mut builder);
-    complete_schemas(&ctx, &mut builder);
-    complete_policies(&ctx, &mut builder);
-    complete_roles(&ctx, &mut builder);
+    complete_tables(&ctx, sanitized_params.schema, &mut builder);
+    complete_functions(&ctx, sanitized_params.schema, &mut builder);
+    complete_columns(&ctx, sanitized_params.schema, &mut builder);
+    complete_schemas(&ctx, sanitized_params.schema, &mut builder);
+    complete_policies(&ctx, sanitized_params.schema, &mut builder);
+    complete_roles(&ctx, sanitized_params.schema, &mut builder);
 
     builder.finish()
 }
diff --git a/crates/pgt_completions/src/lib.rs b/crates/pgt_completions/src/lib.rs
index f8ca1a550..c4e592eef 100644
--- a/crates/pgt_completions/src/lib.rs
+++ b/crates/pgt_completions/src/lib.rs
@@ -1,6 +1,5 @@
 mod builder;
 mod complete;
-mod context;
 mod item;
 mod providers;
 mod relevance;
diff --git a/crates/pgt_completions/src/providers/columns.rs b/crates/pgt_completions/src/providers/columns.rs
index 04d0af656..ba3b24813 100644
--- a/crates/pgt_completions/src/providers/columns.rs
+++ b/crates/pgt_completions/src/providers/columns.rs
@@ -1,14 +1,20 @@
+use pgt_schema_cache::SchemaCache;
+use pgt_treesitter::{TreesitterContext, WrappingClause};
+
 use crate::{
     CompletionItemKind,
     builder::{CompletionBuilder, PossibleCompletionItem},
-    context::{CompletionContext, WrappingClause},
     relevance::{CompletionRelevanceData, filtering::CompletionFilter, scoring::CompletionScore},
 };
 
 use super::helper::{find_matching_alias_for_table, get_completion_text_with_schema_or_alias};
 
-pub fn complete_columns<'a>(ctx: &CompletionContext<'a>, builder: &mut CompletionBuilder<'a>) {
-    let available_columns = &ctx.schema_cache.columns;
+pub fn complete_columns<'a>(
+    ctx: &TreesitterContext<'a>,
+    schema_cache: &'a SchemaCache,
+    builder: &mut CompletionBuilder<'a>,
+) {
+    let available_columns = &schema_cache.columns;
 
     for col in available_columns {
         let relevance = CompletionRelevanceData::Column(col);
@@ -49,11 +55,13 @@ mod tests {
     use crate::{
         CompletionItem, CompletionItemKind, complete,
         test_helper::{
-            CURSOR_POS, CompletionAssertion, InputQuery, assert_complete_results,
-            assert_no_complete_results, get_test_deps, get_test_params,
+            CompletionAssertion, assert_complete_results, assert_no_complete_results,
+            get_test_deps, get_test_params,
         },
     };
 
+    use pgt_test_utils::QueryWithCursorPosition;
+
     struct TestCase {
         query: String,
         message: &'static str,
@@ -62,7 +70,7 @@ mod tests {
     }
 
     impl TestCase {
-        fn get_input_query(&self) -> InputQuery {
+        fn get_input_query(&self) -> QueryWithCursorPosition {
             let strs: Vec<&str> = self.query.split_whitespace().collect();
             strs.join(" ").as_str().into()
         }
@@ -94,7 +102,10 @@ mod tests {
         let queries: Vec<TestCase> = vec![
             TestCase {
                 message: "correctly prefers the columns of present tables",
-                query: format!(r#"select na{} from public.audio_books;"#, CURSOR_POS),
+                query: format!(
+                    r#"select na{} from public.audio_books;"#,
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 label: "narrator",
                 description: "public.audio_books",
             },
@@ -111,14 +122,17 @@ mod tests {
                 join public.users u
                 on u.id = subquery.id;
                 "#,
-                    CURSOR_POS
+                    QueryWithCursorPosition::cursor_marker()
                 ),
                 label: "narrator_id",
                 description: "private.audio_books",
             },
             TestCase {
                 message: "works without a schema",
-                query: format!(r#"select na{} from users;"#, CURSOR_POS),
+                query: format!(
+                    r#"select na{} from users;"#,
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 label: "name",
                 description: "public.users",
             },
@@ -165,7 +179,7 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         let case = TestCase {
-            query: format!(r#"select n{};"#, CURSOR_POS),
+            query: format!(r#"select n{};"#, QueryWithCursorPosition::cursor_marker()),
             description: "",
             label: "",
             message: "",
@@ -220,7 +234,10 @@ mod tests {
 
         let test_case = TestCase {
             message: "suggests user created tables first",
-            query: format!(r#"select {} from users"#, CURSOR_POS),
+            query: format!(
+                r#"select {} from users"#,
+                QueryWithCursorPosition::cursor_marker()
+            ),
             label: "",
             description: "",
         };
@@ -270,7 +287,10 @@ mod tests {
 
         let test_case = TestCase {
             message: "suggests user created tables first",
-            query: format!(r#"select * from private.{}"#, CURSOR_POS),
+            query: format!(
+                r#"select * from private.{}"#,
+                QueryWithCursorPosition::cursor_marker()
+            ),
             label: "",
             description: "",
         };
@@ -311,7 +331,11 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         assert_complete_results(
-            format!(r#"select {} from users"#, CURSOR_POS).as_str(),
+            format!(
+                r#"select {} from users"#,
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("address2".into()),
                 CompletionAssertion::Label("email2".into()),
@@ -324,7 +348,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!(r#"select {} from private.users"#, CURSOR_POS).as_str(),
+            format!(
+                r#"select {} from private.users"#,
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("address1".into()),
                 CompletionAssertion::Label("email1".into()),
@@ -338,7 +366,11 @@ mod tests {
 
         // asserts fuzzy finding for "settings"
         assert_complete_results(
-            format!(r#"select sett{} from private.users"#, CURSOR_POS).as_str(),
+            format!(
+                r#"select sett{} from private.users"#,
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![CompletionAssertion::Label("user_settings".into())],
             None,
             &pool,
@@ -372,7 +404,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select u.id, p.{} from auth.users u join auth.posts p on u.id = p.user_id;",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -394,7 +426,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select u.id, p.content from auth.users u join auth.posts p on u.id = p.{};",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -440,7 +472,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select u.id, p.content from auth.users u join auth.{}",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -479,7 +511,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select u.id, auth.posts.content from auth.users u join auth.posts on u.{}",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -496,7 +528,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select u.id, p.content from auth.users u join auth.posts p on p.user_id = u.{}",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -536,7 +568,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select {} from public.one o join public.two on o.id = t.id;",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -555,7 +587,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select a, {} from public.one o join public.two on o.id = t.id;",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -577,7 +609,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select o.id, a, b, c, d, e, {} from public.one o join public.two on o.id = t.id;",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -593,7 +625,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select id, a, b, c, d, e, {} from public.one o join public.two on o.id = t.id;",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![CompletionAssertion::Label("z".to_string())],
@@ -625,7 +657,11 @@ mod tests {
         // are lower in the alphabet
 
         assert_complete_results(
-            format!("insert into instruments ({})", CURSOR_POS).as_str(),
+            format!(
+                "insert into instruments ({})",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("id".to_string()),
                 CompletionAssertion::Label("name".to_string()),
@@ -637,7 +673,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("insert into instruments (id, {})", CURSOR_POS).as_str(),
+            format!(
+                "insert into instruments (id, {})",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("name".to_string()),
                 CompletionAssertion::Label("z".to_string()),
@@ -648,7 +688,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("insert into instruments (id, {}, name)", CURSOR_POS).as_str(),
+            format!(
+                "insert into instruments (id, {}, name)",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![CompletionAssertion::Label("z".to_string())],
             None,
             &pool,
@@ -659,7 +703,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "insert into instruments (name, {}) values ('my_bass');",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -673,7 +717,11 @@ mod tests {
 
         // no completions in the values list!
         assert_no_complete_results(
-            format!("insert into instruments (id, name) values ({})", CURSOR_POS).as_str(),
+            format!(
+                "insert into instruments (id, name) values ({})",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             None,
             &pool,
         )
@@ -700,7 +748,11 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         assert_complete_results(
-            format!("select name from instruments where {} ", CURSOR_POS).as_str(),
+            format!(
+                "select name from instruments where {} ",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("created_at".into()),
                 CompletionAssertion::Label("id".into()),
@@ -715,7 +767,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select name from instruments where z = 'something' and created_at > {}",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             // simply do not complete columns + schemas; functions etc. are ok
@@ -732,7 +784,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select name from instruments where id = 'something' and {}",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -749,7 +801,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "select name from instruments i join others o on i.z = o.a where i.{}",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -783,22 +835,37 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         let queries = vec![
-            format!("alter table instruments drop column {}", CURSOR_POS),
+            format!(
+                "alter table instruments drop column {}",
+                QueryWithCursorPosition::cursor_marker()
+            ),
             format!(
                 "alter table instruments drop column if exists {}",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ),
             format!(
                 "alter table instruments alter column {} set default",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "alter table instruments alter {} set default",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "alter table public.instruments alter column {}",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "alter table instruments alter {}",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "alter table instruments rename {} to new_col",
+                QueryWithCursorPosition::cursor_marker()
             ),
-            format!("alter table instruments alter {} set default", CURSOR_POS),
-            format!("alter table public.instruments alter column {}", CURSOR_POS),
-            format!("alter table instruments alter {}", CURSOR_POS),
-            format!("alter table instruments rename {} to new_col", CURSOR_POS),
             format!(
                 "alter table public.instruments rename column {} to new_col",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ),
         ];
 
@@ -834,19 +901,19 @@ mod tests {
         let col_queries = vec![
             format!(
                 r#"create policy "my_pol" on public.instruments for select using ({})"#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ),
             format!(
                 r#"create policy "my_pol" on public.instruments for insert with check ({})"#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ),
             format!(
                 r#"create policy "my_pol" on public.instruments for update using (id = 1 and {})"#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ),
             format!(
                 r#"create policy "my_pol" on public.instruments for insert with check (id = 1 and {})"#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ),
         ];
 
diff --git a/crates/pgt_completions/src/providers/functions.rs b/crates/pgt_completions/src/providers/functions.rs
index 615e4f951..b2ac2fae8 100644
--- a/crates/pgt_completions/src/providers/functions.rs
+++ b/crates/pgt_completions/src/providers/functions.rs
@@ -1,17 +1,21 @@
-use pgt_schema_cache::Function;
+use pgt_schema_cache::{Function, SchemaCache};
+use pgt_treesitter::TreesitterContext;
 
 use crate::{
     CompletionItemKind, CompletionText,
     builder::{CompletionBuilder, PossibleCompletionItem},
-    context::CompletionContext,
     providers::helper::get_range_to_replace,
     relevance::{CompletionRelevanceData, filtering::CompletionFilter, scoring::CompletionScore},
 };
 
 use super::helper::get_completion_text_with_schema_or_alias;
 
-pub fn complete_functions<'a>(ctx: &'a CompletionContext, builder: &mut CompletionBuilder<'a>) {
-    let available_functions = &ctx.schema_cache.functions;
+pub fn complete_functions<'a>(
+    ctx: &'a TreesitterContext,
+    schema_cache: &'a SchemaCache,
+    builder: &mut CompletionBuilder<'a>,
+) {
+    let available_functions = &schema_cache.functions;
 
     for func in available_functions {
         let relevance = CompletionRelevanceData::Function(func);
@@ -30,7 +34,7 @@ pub fn complete_functions<'a>(ctx: &'a CompletionContext, builder: &mut Completi
     }
 }
 
-fn get_completion_text(ctx: &CompletionContext, func: &Function) -> CompletionText {
+fn get_completion_text(ctx: &TreesitterContext, func: &Function) -> CompletionText {
     let range = get_range_to_replace(ctx);
     let mut text = get_completion_text_with_schema_or_alias(ctx, &func.name, &func.schema)
         .map(|ct| ct.text)
@@ -70,11 +74,12 @@ mod tests {
     use crate::{
         CompletionItem, CompletionItemKind, complete,
         test_helper::{
-            CURSOR_POS, CompletionAssertion, assert_complete_results, get_test_deps,
-            get_test_params,
+            CompletionAssertion, assert_complete_results, get_test_deps, get_test_params,
         },
     };
 
+    use pgt_test_utils::QueryWithCursorPosition;
+
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn completes_fn(pool: PgPool) {
         let setup = r#"
@@ -89,7 +94,7 @@ mod tests {
           $$;
         "#;
 
-        let query = format!("select coo{}", CURSOR_POS);
+        let query = format!("select coo{}", QueryWithCursorPosition::cursor_marker());
 
         let (tree, cache) = get_test_deps(Some(setup), query.as_str().into(), &pool).await;
         let params = get_test_params(&tree, &cache, query.as_str().into());
@@ -122,7 +127,10 @@ mod tests {
           $$;
         "#;
 
-        let query = format!(r#"select * from coo{}()"#, CURSOR_POS);
+        let query = format!(
+            r#"select * from coo{}()"#,
+            QueryWithCursorPosition::cursor_marker()
+        );
 
         let (tree, cache) = get_test_deps(Some(setup), query.as_str().into(), &pool).await;
         let params = get_test_params(&tree, &cache, query.as_str().into());
@@ -156,7 +164,7 @@ mod tests {
           $$;
         "#;
 
-        let query = format!(r#"select coo{}"#, CURSOR_POS);
+        let query = format!(r#"select coo{}"#, QueryWithCursorPosition::cursor_marker());
 
         let (tree, cache) = get_test_deps(Some(setup), query.as_str().into(), &pool).await;
         let params = get_test_params(&tree, &cache, query.as_str().into());
@@ -190,7 +198,10 @@ mod tests {
           $$;
         "#;
 
-        let query = format!(r#"select * from coo{}()"#, CURSOR_POS);
+        let query = format!(
+            r#"select * from coo{}()"#,
+            QueryWithCursorPosition::cursor_marker()
+        );
 
         let (tree, cache) = get_test_deps(Some(setup), query.as_str().into(), &pool).await;
         let params = get_test_params(&tree, &cache, query.as_str().into());
@@ -259,7 +270,7 @@ mod tests {
 
         let query = format!(
             r#"create policy "my_pol" on public.instruments for insert with check (id = {})"#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         );
 
         assert_complete_results(
diff --git a/crates/pgt_completions/src/providers/helper.rs b/crates/pgt_completions/src/providers/helper.rs
index 811125bd1..cd1046f12 100644
--- a/crates/pgt_completions/src/providers/helper.rs
+++ b/crates/pgt_completions/src/providers/helper.rs
@@ -1,9 +1,10 @@
 use pgt_text_size::{TextRange, TextSize};
+use pgt_treesitter::TreesitterContext;
 
-use crate::{CompletionText, context::CompletionContext, remove_sanitized_token};
+use crate::{CompletionText, remove_sanitized_token};
 
 pub(crate) fn find_matching_alias_for_table(
-    ctx: &CompletionContext,
+    ctx: &TreesitterContext,
     table_name: &str,
 ) -> Option<String> {
     for (alias, table) in ctx.mentioned_table_aliases.iter() {
@@ -14,7 +15,7 @@ pub(crate) fn find_matching_alias_for_table(
     None
 }
 
-pub(crate) fn get_range_to_replace(ctx: &CompletionContext) -> TextRange {
+pub(crate) fn get_range_to_replace(ctx: &TreesitterContext) -> TextRange {
     match ctx.node_under_cursor.as_ref() {
         Some(node) => {
             let content = ctx.get_node_under_cursor_content().unwrap_or("".into());
@@ -30,7 +31,7 @@ pub(crate) fn get_range_to_replace(ctx: &CompletionContext) -> TextRange {
 }
 
 pub(crate) fn get_completion_text_with_schema_or_alias(
-    ctx: &CompletionContext,
+    ctx: &TreesitterContext,
     item_name: &str,
     schema_or_alias_name: &str,
 ) -> Option<CompletionText> {
diff --git a/crates/pgt_completions/src/providers/policies.rs b/crates/pgt_completions/src/providers/policies.rs
index 216fcefaa..a5ffdb43e 100644
--- a/crates/pgt_completions/src/providers/policies.rs
+++ b/crates/pgt_completions/src/providers/policies.rs
@@ -1,16 +1,21 @@
+use pgt_schema_cache::SchemaCache;
 use pgt_text_size::{TextRange, TextSize};
+use pgt_treesitter::TreesitterContext;
 
 use crate::{
     CompletionItemKind, CompletionText,
     builder::{CompletionBuilder, PossibleCompletionItem},
-    context::CompletionContext,
     relevance::{CompletionRelevanceData, filtering::CompletionFilter, scoring::CompletionScore},
 };
 
 use super::helper::get_range_to_replace;
 
-pub fn complete_policies<'a>(ctx: &CompletionContext<'a>, builder: &mut CompletionBuilder<'a>) {
-    let available_policies = &ctx.schema_cache.policies;
+pub fn complete_policies<'a>(
+    ctx: &TreesitterContext<'a>,
+    schema_cache: &'a SchemaCache,
+    builder: &mut CompletionBuilder<'a>,
+) {
+    let available_policies = &schema_cache.policies;
 
     let surrounded_by_quotes = ctx
         .get_node_under_cursor_content()
@@ -61,7 +66,8 @@ pub fn complete_policies<'a>(ctx: &CompletionContext<'a>, builder: &mut Completi
 mod tests {
     use sqlx::{Executor, PgPool};
 
-    use crate::test_helper::{CURSOR_POS, CompletionAssertion, assert_complete_results};
+    use crate::test_helper::{CompletionAssertion, assert_complete_results};
+    use pgt_test_utils::QueryWithCursorPosition;
 
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn completes_within_quotation_marks(pool: PgPool) {
@@ -89,7 +95,11 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         assert_complete_results(
-            format!("alter policy \"{}\" on private.users;", CURSOR_POS).as_str(),
+            format!(
+                "alter policy \"{}\" on private.users;",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("read for public users disallowed".into()),
                 CompletionAssertion::Label("write for public users allowed".into()),
@@ -100,7 +110,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("alter policy \"w{}\" on private.users;", CURSOR_POS).as_str(),
+            format!(
+                "alter policy \"w{}\" on private.users;",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![CompletionAssertion::Label(
                 "write for public users allowed".into(),
             )],
diff --git a/crates/pgt_completions/src/providers/roles.rs b/crates/pgt_completions/src/providers/roles.rs
index 01641543f..b7664349c 100644
--- a/crates/pgt_completions/src/providers/roles.rs
+++ b/crates/pgt_completions/src/providers/roles.rs
@@ -1,12 +1,17 @@
 use crate::{
     CompletionItemKind,
     builder::{CompletionBuilder, PossibleCompletionItem},
-    context::CompletionContext,
     relevance::{CompletionRelevanceData, filtering::CompletionFilter, scoring::CompletionScore},
 };
+use pgt_schema_cache::SchemaCache;
+use pgt_treesitter::TreesitterContext;
 
-pub fn complete_roles<'a>(ctx: &CompletionContext<'a>, builder: &mut CompletionBuilder<'a>) {
-    let available_roles = &ctx.schema_cache.roles;
+pub fn complete_roles<'a>(
+    _ctx: &TreesitterContext<'a>,
+    schema_cache: &'a SchemaCache,
+    builder: &mut CompletionBuilder<'a>,
+) {
+    let available_roles = &schema_cache.roles;
 
     for role in available_roles {
         let relevance = CompletionRelevanceData::Role(role);
@@ -29,7 +34,9 @@ pub fn complete_roles<'a>(ctx: &CompletionContext<'a>, builder: &mut CompletionB
 mod tests {
     use sqlx::{Executor, PgPool};
 
-    use crate::test_helper::{CURSOR_POS, CompletionAssertion, assert_complete_results};
+    use crate::test_helper::{CompletionAssertion, assert_complete_results};
+
+    use pgt_test_utils::QueryWithCursorPosition;
 
     const SETUP: &str = r#"
             create table users (
@@ -42,7 +49,7 @@ mod tests {
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn works_in_drop_role(pool: PgPool) {
         assert_complete_results(
-            format!("drop role {}", CURSOR_POS).as_str(),
+            format!("drop role {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("owner".into(), crate::CompletionItemKind::Role),
                 CompletionAssertion::LabelAndKind(
@@ -63,7 +70,7 @@ mod tests {
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn works_in_alter_role(pool: PgPool) {
         assert_complete_results(
-            format!("alter role {}", CURSOR_POS).as_str(),
+            format!("alter role {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("owner".into(), crate::CompletionItemKind::Role),
                 CompletionAssertion::LabelAndKind(
@@ -86,7 +93,7 @@ mod tests {
         pool.execute(SETUP).await.unwrap();
 
         assert_complete_results(
-            format!("set role {}", CURSOR_POS).as_str(),
+            format!("set role {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("owner".into(), crate::CompletionItemKind::Role),
                 CompletionAssertion::LabelAndKind(
@@ -104,7 +111,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("set session authorization {}", CURSOR_POS).as_str(),
+            format!(
+                "set session authorization {}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("owner".into(), crate::CompletionItemKind::Role),
                 CompletionAssertion::LabelAndKind(
@@ -133,7 +144,7 @@ mod tests {
             for all
             to {}
             using (true);"#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -157,7 +168,7 @@ mod tests {
                 r#"create policy "my cool policy" on public.users
             for select
             to {}"#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -186,7 +197,7 @@ mod tests {
                 r#"grant select
                     on table public.users
                     to {}"#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -211,7 +222,7 @@ mod tests {
                 r#"grant select
                     on table public.users
                     to owner, {}"#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
@@ -232,7 +243,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!(r#"grant {} to owner"#, CURSOR_POS).as_str(),
+            format!(
+                r#"grant {} to owner"#,
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 // recognizing already mentioned roles is not supported for now
                 CompletionAssertion::LabelAndKind("owner".into(), crate::CompletionItemKind::Role),
@@ -256,12 +271,30 @@ mod tests {
         pool.execute(SETUP).await.unwrap();
 
         let queries = vec![
-            format!("revoke {} from owner", CURSOR_POS),
-            format!("revoke admin option for {} from owner", CURSOR_POS),
-            format!("revoke owner from {}", CURSOR_POS),
-            format!("revoke all on schema public from {} granted by", CURSOR_POS),
-            format!("revoke all on schema public from owner, {}", CURSOR_POS),
-            format!("revoke all on table userse from owner, {}", CURSOR_POS),
+            format!(
+                "revoke {} from owner",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "revoke admin option for {} from owner",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "revoke owner from {}",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "revoke all on schema public from {} granted by",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "revoke all on schema public from owner, {}",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                "revoke all on table userse from owner, {}",
+                QueryWithCursorPosition::cursor_marker()
+            ),
         ];
 
         for query in queries {
diff --git a/crates/pgt_completions/src/providers/schemas.rs b/crates/pgt_completions/src/providers/schemas.rs
index 561da0f85..43c523875 100644
--- a/crates/pgt_completions/src/providers/schemas.rs
+++ b/crates/pgt_completions/src/providers/schemas.rs
@@ -1,11 +1,16 @@
 use crate::{
     builder::{CompletionBuilder, PossibleCompletionItem},
-    context::CompletionContext,
     relevance::{CompletionRelevanceData, filtering::CompletionFilter, scoring::CompletionScore},
 };
+use pgt_schema_cache::SchemaCache;
+use pgt_treesitter::TreesitterContext;
 
-pub fn complete_schemas<'a>(ctx: &'a CompletionContext, builder: &mut CompletionBuilder<'a>) {
-    let available_schemas = &ctx.schema_cache.schemas;
+pub fn complete_schemas<'a>(
+    _ctx: &'a TreesitterContext,
+    schema_cache: &'a SchemaCache,
+    builder: &mut CompletionBuilder<'a>,
+) {
+    let available_schemas = &schema_cache.schemas;
 
     for schema in available_schemas {
         let relevance = CompletionRelevanceData::Schema(schema);
@@ -31,9 +36,11 @@ mod tests {
 
     use crate::{
         CompletionItemKind,
-        test_helper::{CURSOR_POS, CompletionAssertion, assert_complete_results},
+        test_helper::{CompletionAssertion, assert_complete_results},
     };
 
+    use pgt_test_utils::QueryWithCursorPosition;
+
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn autocompletes_schemas(pool: PgPool) {
         let setup = r#"
@@ -50,7 +57,7 @@ mod tests {
         "#;
 
         assert_complete_results(
-            format!("select * from {}", CURSOR_POS).as_str(),
+            format!("select * from {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("public".to_string(), CompletionItemKind::Schema),
                 CompletionAssertion::LabelAndKind("auth".to_string(), CompletionItemKind::Schema),
@@ -97,7 +104,11 @@ mod tests {
         "#;
 
         assert_complete_results(
-            format!("select * from u{}", CURSOR_POS).as_str(),
+            format!(
+                "select * from u{}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("users".into(), CompletionItemKind::Table),
                 CompletionAssertion::LabelAndKind("ultimate".into(), CompletionItemKind::Schema),
diff --git a/crates/pgt_completions/src/providers/tables.rs b/crates/pgt_completions/src/providers/tables.rs
index 3fbee8f12..f78b697c9 100644
--- a/crates/pgt_completions/src/providers/tables.rs
+++ b/crates/pgt_completions/src/providers/tables.rs
@@ -1,14 +1,20 @@
+use pgt_schema_cache::SchemaCache;
+use pgt_treesitter::TreesitterContext;
+
 use crate::{
     builder::{CompletionBuilder, PossibleCompletionItem},
-    context::CompletionContext,
     item::CompletionItemKind,
     relevance::{CompletionRelevanceData, filtering::CompletionFilter, scoring::CompletionScore},
 };
 
 use super::helper::get_completion_text_with_schema_or_alias;
 
-pub fn complete_tables<'a>(ctx: &'a CompletionContext, builder: &mut CompletionBuilder<'a>) {
-    let available_tables = &ctx.schema_cache.tables;
+pub fn complete_tables<'a>(
+    ctx: &'a TreesitterContext,
+    schema_cache: &'a SchemaCache,
+    builder: &mut CompletionBuilder<'a>,
+) {
+    let available_tables = &schema_cache.tables;
 
     for table in available_tables {
         let relevance = CompletionRelevanceData::Table(table);
@@ -47,11 +53,13 @@ mod tests {
     use crate::{
         CompletionItem, CompletionItemKind, complete,
         test_helper::{
-            CURSOR_POS, CompletionAssertion, assert_complete_results, assert_no_complete_results,
+            CompletionAssertion, assert_complete_results, assert_no_complete_results,
             get_test_deps, get_test_params,
         },
     };
 
+    use pgt_test_utils::QueryWithCursorPosition;
+
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn autocompletes_simple_table(pool: PgPool) {
         let setup = r#"
@@ -62,7 +70,10 @@ mod tests {
             );
         "#;
 
-        let query = format!("select * from u{}", CURSOR_POS);
+        let query = format!(
+            "select * from u{}",
+            QueryWithCursorPosition::cursor_marker()
+        );
 
         let (tree, cache) = get_test_deps(Some(setup), query.as_str().into(), &pool).await;
         let params = get_test_params(&tree, &cache, query.as_str().into());
@@ -98,9 +109,27 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         let test_cases = vec![
-            (format!("select * from u{}", CURSOR_POS), "users"),
-            (format!("select * from e{}", CURSOR_POS), "emails"),
-            (format!("select * from a{}", CURSOR_POS), "addresses"),
+            (
+                format!(
+                    "select * from u{}",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                "users",
+            ),
+            (
+                format!(
+                    "select * from e{}",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                "emails",
+            ),
+            (
+                format!(
+                    "select * from a{}",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                "addresses",
+            ),
         ];
 
         for (query, expected_label) in test_cases {
@@ -142,10 +171,25 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         let test_cases = vec![
-            (format!("select * from u{}", CURSOR_POS), "user_y"), // user_y is preferred alphanumerically
-            (format!("select * from private.u{}", CURSOR_POS), "user_z"),
             (
-                format!("select * from customer_support.u{}", CURSOR_POS),
+                format!(
+                    "select * from u{}",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                "user_y",
+            ), // user_y is preferred alphanumerically
+            (
+                format!(
+                    "select * from private.u{}",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                "user_z",
+            ),
+            (
+                format!(
+                    "select * from customer_support.u{}",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 "user_y",
             ),
         ];
@@ -186,7 +230,10 @@ mod tests {
           $$;
         "#;
 
-        let query = format!(r#"select * from coo{}"#, CURSOR_POS);
+        let query = format!(
+            r#"select * from coo{}"#,
+            QueryWithCursorPosition::cursor_marker()
+        );
 
         let (tree, cache) = get_test_deps(Some(setup), query.as_str().into(), &pool).await;
         let params = get_test_params(&tree, &cache, query.as_str().into());
@@ -213,7 +260,7 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         assert_complete_results(
-            format!("update {}", CURSOR_POS).as_str(),
+            format!("update {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![CompletionAssertion::LabelAndKind(
                 "public".into(),
                 CompletionItemKind::Schema,
@@ -224,7 +271,7 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("update public.{}", CURSOR_POS).as_str(),
+            format!("update public.{}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![CompletionAssertion::LabelAndKind(
                 "coos".into(),
                 CompletionItemKind::Table,
@@ -235,14 +282,22 @@ mod tests {
         .await;
 
         assert_no_complete_results(
-            format!("update public.coos {}", CURSOR_POS).as_str(),
+            format!(
+                "update public.coos {}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             None,
             &pool,
         )
         .await;
 
         assert_complete_results(
-            format!("update coos set {}", CURSOR_POS).as_str(),
+            format!(
+                "update coos set {}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("id".into()),
                 CompletionAssertion::Label("name".into()),
@@ -253,7 +308,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("update coos set name = 'cool' where {}", CURSOR_POS).as_str(),
+            format!(
+                "update coos set name = 'cool' where {}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("id".into()),
                 CompletionAssertion::Label("name".into()),
@@ -275,10 +334,15 @@ mod tests {
 
         pool.execute(setup).await.unwrap();
 
-        assert_no_complete_results(format!("delete {}", CURSOR_POS).as_str(), None, &pool).await;
+        assert_no_complete_results(
+            format!("delete {}", QueryWithCursorPosition::cursor_marker()).as_str(),
+            None,
+            &pool,
+        )
+        .await;
 
         assert_complete_results(
-            format!("delete from {}", CURSOR_POS).as_str(),
+            format!("delete from {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("public".into(), CompletionItemKind::Schema),
                 CompletionAssertion::LabelAndKind("coos".into(), CompletionItemKind::Table),
@@ -289,7 +353,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("delete from public.{}", CURSOR_POS).as_str(),
+            format!(
+                "delete from public.{}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![CompletionAssertion::Label("coos".into())],
             None,
             &pool,
@@ -297,7 +365,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("delete from public.coos where {}", CURSOR_POS).as_str(),
+            format!(
+                "delete from public.coos where {}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::Label("id".into()),
                 CompletionAssertion::Label("name".into()),
@@ -329,7 +401,11 @@ mod tests {
         "#;
 
         assert_complete_results(
-            format!("select * from auth.users u join {}", CURSOR_POS).as_str(),
+            format!(
+                "select * from auth.users u join {}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("public".into(), CompletionItemKind::Schema),
                 CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema),
@@ -365,7 +441,7 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         assert_complete_results(
-            format!("alter table {}", CURSOR_POS).as_str(),
+            format!("alter table {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("public".into(), CompletionItemKind::Schema),
                 CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema),
@@ -378,7 +454,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("alter table if exists {}", CURSOR_POS).as_str(),
+            format!(
+                "alter table if exists {}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("public".into(), CompletionItemKind::Schema),
                 CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema),
@@ -391,7 +471,7 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("drop table {}", CURSOR_POS).as_str(),
+            format!("drop table {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("public".into(), CompletionItemKind::Schema),
                 CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema),
@@ -404,7 +484,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("drop table if exists {}", CURSOR_POS).as_str(),
+            format!(
+                "drop table if exists {}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("public".into(), CompletionItemKind::Schema),
                 CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema),
@@ -432,7 +516,7 @@ mod tests {
         pool.execute(setup).await.unwrap();
 
         assert_complete_results(
-            format!("insert into {}", CURSOR_POS).as_str(),
+            format!("insert into {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::LabelAndKind("public".into(), CompletionItemKind::Schema),
                 CompletionAssertion::LabelAndKind("auth".into(), CompletionItemKind::Schema),
@@ -444,7 +528,11 @@ mod tests {
         .await;
 
         assert_complete_results(
-            format!("insert into auth.{}", CURSOR_POS).as_str(),
+            format!(
+                "insert into auth.{}",
+                QueryWithCursorPosition::cursor_marker()
+            )
+            .as_str(),
             vec![CompletionAssertion::LabelAndKind(
                 "users".into(),
                 CompletionItemKind::Table,
@@ -458,7 +546,7 @@ mod tests {
         assert_complete_results(
             format!(
                 "insert into {} (name, email) values ('jules', 'a@b.com');",
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             )
             .as_str(),
             vec![
diff --git a/crates/pgt_completions/src/providers/triggers.rs b/crates/pgt_completions/src/providers/triggers.rs
deleted file mode 100644
index 6bc04debc..000000000
--- a/crates/pgt_completions/src/providers/triggers.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-use crate::{
-    CompletionItemKind,
-    builder::{CompletionBuilder, PossibleCompletionItem},
-    context::CompletionContext,
-    relevance::{CompletionRelevanceData, filtering::CompletionFilter, scoring::CompletionScore},
-};
-
-use super::helper::get_completion_text_with_schema_or_alias;
-
-pub fn complete_functions<'a>(ctx: &'a CompletionContext, builder: &mut CompletionBuilder<'a>) {
-    let available_functions = &ctx.schema_cache.functions;
-
-    for func in available_functions {
-        let relevance = CompletionRelevanceData::Function(func);
-
-        let item = PossibleCompletionItem {
-            label: func.name.clone(),
-            score: CompletionScore::from(relevance.clone()),
-            filter: CompletionFilter::from(relevance),
-            description: format!("Schema: {}", func.schema),
-            kind: CompletionItemKind::Function,
-            completion_text: get_completion_text_with_schema_or_alias(
-                ctx,
-                &func.name,
-                &func.schema,
-            ),
-        };
-
-        builder.add_item(item);
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::{
-        CompletionItem, CompletionItemKind, complete,
-        test_helper::{CURSOR_POS, get_test_deps, get_test_params},
-    };
-
-    #[tokio::test]
-    async fn completes_fn() {
-        let setup = r#"
-          create or replace function cool()
-          returns trigger
-          language plpgsql
-          security invoker
-          as $$
-          begin
-            raise exception 'dont matter';
-          end;
-          $$;
-        "#;
-
-        let query = format!("select coo{}", CURSOR_POS);
-
-        let (tree, cache) = get_test_deps(setup, query.as_str().into()).await;
-        let params = get_test_params(&tree, &cache, query.as_str().into());
-        let results = complete(params);
-
-        let CompletionItem { label, .. } = results
-            .into_iter()
-            .next()
-            .expect("Should return at least one completion item");
-
-        assert_eq!(label, "cool");
-    }
-
-    #[tokio::test]
-    async fn prefers_fn_if_invocation() {
-        let setup = r#"
-          create table coos (
-            id serial primary key,
-            name text
-          );
-
-          create or replace function cool()
-          returns trigger
-          language plpgsql
-          security invoker
-          as $$
-          begin
-            raise exception 'dont matter';
-          end;
-          $$;
-        "#;
-
-        let query = format!(r#"select * from coo{}()"#, CURSOR_POS);
-
-        let (tree, cache) = get_test_deps(setup, query.as_str().into()).await;
-        let params = get_test_params(&tree, &cache, query.as_str().into());
-        let results = complete(params);
-
-        let CompletionItem { label, kind, .. } = results
-            .into_iter()
-            .next()
-            .expect("Should return at least one completion item");
-
-        assert_eq!(label, "cool");
-        assert_eq!(kind, CompletionItemKind::Function);
-    }
-
-    #[tokio::test]
-    async fn prefers_fn_in_select_clause() {
-        let setup = r#"
-          create table coos (
-            id serial primary key,
-            name text
-          );
-
-          create or replace function cool()
-          returns trigger
-          language plpgsql
-          security invoker
-          as $$
-          begin
-            raise exception 'dont matter';
-          end;
-          $$;
-        "#;
-
-        let query = format!(r#"select coo{}"#, CURSOR_POS);
-
-        let (tree, cache) = get_test_deps(setup, query.as_str().into()).await;
-        let params = get_test_params(&tree, &cache, query.as_str().into());
-        let results = complete(params);
-
-        let CompletionItem { label, kind, .. } = results
-            .into_iter()
-            .next()
-            .expect("Should return at least one completion item");
-
-        assert_eq!(label, "cool");
-        assert_eq!(kind, CompletionItemKind::Function);
-    }
-
-    #[tokio::test]
-    async fn prefers_function_in_from_clause_if_invocation() {
-        let setup = r#"
-          create table coos (
-            id serial primary key,
-            name text
-          );
-
-          create or replace function cool()
-          returns trigger
-          language plpgsql
-          security invoker
-          as $$
-          begin
-            raise exception 'dont matter';
-          end;
-          $$;
-        "#;
-
-        let query = format!(r#"select * from coo{}()"#, CURSOR_POS);
-
-        let (tree, cache) = get_test_deps(setup, query.as_str().into()).await;
-        let params = get_test_params(&tree, &cache, query.as_str().into());
-        let results = complete(params);
-
-        let CompletionItem { label, kind, .. } = results
-            .into_iter()
-            .next()
-            .expect("Should return at least one completion item");
-
-        assert_eq!(label, "cool");
-        assert_eq!(kind, CompletionItemKind::Function);
-    }
-}
diff --git a/crates/pgt_completions/src/relevance/filtering.rs b/crates/pgt_completions/src/relevance/filtering.rs
index beea6ddb8..18e3d7ce5 100644
--- a/crates/pgt_completions/src/relevance/filtering.rs
+++ b/crates/pgt_completions/src/relevance/filtering.rs
@@ -1,6 +1,6 @@
 use pgt_schema_cache::ProcKind;
 
-use crate::context::{CompletionContext, NodeUnderCursor, WrappingClause, WrappingNode};
+use pgt_treesitter::context::{NodeUnderCursor, TreesitterContext, WrappingClause, WrappingNode};
 
 use super::CompletionRelevanceData;
 
@@ -16,7 +16,7 @@ impl<'a> From<CompletionRelevanceData<'a>> for CompletionFilter<'a> {
 }
 
 impl CompletionFilter<'_> {
-    pub fn is_relevant(&self, ctx: &CompletionContext) -> Option<()> {
+    pub fn is_relevant(&self, ctx: &TreesitterContext) -> Option<()> {
         self.completable_context(ctx)?;
         self.check_clause(ctx)?;
         self.check_invocation(ctx)?;
@@ -25,7 +25,7 @@ impl CompletionFilter<'_> {
         Some(())
     }
 
-    fn completable_context(&self, ctx: &CompletionContext) -> Option<()> {
+    fn completable_context(&self, ctx: &TreesitterContext) -> Option<()> {
         if ctx.wrapping_node_kind.is_none() && ctx.wrapping_clause_type.is_none() {
             return None;
         }
@@ -70,7 +70,7 @@ impl CompletionFilter<'_> {
         Some(())
     }
 
-    fn check_clause(&self, ctx: &CompletionContext) -> Option<()> {
+    fn check_clause(&self, ctx: &TreesitterContext) -> Option<()> {
         ctx.wrapping_clause_type
             .as_ref()
             .map(|clause| {
@@ -208,7 +208,7 @@ impl CompletionFilter<'_> {
             .and_then(|is_ok| if is_ok { Some(()) } else { None })
     }
 
-    fn check_invocation(&self, ctx: &CompletionContext) -> Option<()> {
+    fn check_invocation(&self, ctx: &TreesitterContext) -> Option<()> {
         if !ctx.is_invocation {
             return Some(());
         }
@@ -221,7 +221,7 @@ impl CompletionFilter<'_> {
         Some(())
     }
 
-    fn check_mentioned_schema_or_alias(&self, ctx: &CompletionContext) -> Option<()> {
+    fn check_mentioned_schema_or_alias(&self, ctx: &TreesitterContext) -> Option<()> {
         if ctx.schema_or_alias_name.is_none() {
             return Some(());
         }
@@ -255,9 +255,11 @@ mod tests {
     use sqlx::{Executor, PgPool};
 
     use crate::test_helper::{
-        CURSOR_POS, CompletionAssertion, assert_complete_results, assert_no_complete_results,
+        CompletionAssertion, assert_complete_results, assert_no_complete_results,
     };
 
+    use pgt_test_utils::QueryWithCursorPosition;
+
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn completion_after_asterisk(pool: PgPool) {
         let setup = r#"
@@ -270,11 +272,16 @@ mod tests {
 
         pool.execute(setup).await.unwrap();
 
-        assert_no_complete_results(format!("select * {}", CURSOR_POS).as_str(), None, &pool).await;
+        assert_no_complete_results(
+            format!("select * {}", QueryWithCursorPosition::cursor_marker()).as_str(),
+            None,
+            &pool,
+        )
+        .await;
 
         // if there s a COMMA after the asterisk, we're good
         assert_complete_results(
-            format!("select *, {}", CURSOR_POS).as_str(),
+            format!("select *, {}", QueryWithCursorPosition::cursor_marker()).as_str(),
             vec![
                 CompletionAssertion::Label("address".into()),
                 CompletionAssertion::Label("email".into()),
@@ -288,13 +295,20 @@ mod tests {
 
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn completion_after_create_table(pool: PgPool) {
-        assert_no_complete_results(format!("create table {}", CURSOR_POS).as_str(), None, &pool)
-            .await;
+        assert_no_complete_results(
+            format!("create table {}", QueryWithCursorPosition::cursor_marker()).as_str(),
+            None,
+            &pool,
+        )
+        .await;
     }
 
     #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
     async fn completion_in_column_definitions(pool: PgPool) {
-        let query = format!(r#"create table instruments ( {} )"#, CURSOR_POS);
+        let query = format!(
+            r#"create table instruments ( {} )"#,
+            QueryWithCursorPosition::cursor_marker()
+        );
         assert_no_complete_results(query.as_str(), None, &pool).await;
     }
 }
diff --git a/crates/pgt_completions/src/relevance/scoring.rs b/crates/pgt_completions/src/relevance/scoring.rs
index a0b5efa53..4bbf325f4 100644
--- a/crates/pgt_completions/src/relevance/scoring.rs
+++ b/crates/pgt_completions/src/relevance/scoring.rs
@@ -1,6 +1,8 @@
 use fuzzy_matcher::{FuzzyMatcher, skim::SkimMatcherV2};
 
-use crate::context::{CompletionContext, WrappingClause, WrappingNode};
+use pgt_treesitter::context::{TreesitterContext, WrappingClause, WrappingNode};
+
+use crate::sanitization;
 
 use super::CompletionRelevanceData;
 
@@ -24,7 +26,7 @@ impl CompletionScore<'_> {
         self.score
     }
 
-    pub fn calc_score(&mut self, ctx: &CompletionContext) {
+    pub fn calc_score(&mut self, ctx: &TreesitterContext) {
         self.check_is_user_defined();
         self.check_matches_schema(ctx);
         self.check_matches_query_input(ctx);
@@ -35,10 +37,10 @@ impl CompletionScore<'_> {
         self.check_columns_in_stmt(ctx);
     }
 
-    fn check_matches_query_input(&mut self, ctx: &CompletionContext) {
+    fn check_matches_query_input(&mut self, ctx: &TreesitterContext) {
         let content = match ctx.get_node_under_cursor_content() {
-            Some(c) => c.replace('"', ""),
-            None => return,
+            Some(c) if !sanitization::is_sanitized_token(c.as_str()) => c.replace('"', ""),
+            _ => return,
         };
 
         let name = match self.data {
@@ -69,7 +71,7 @@ impl CompletionScore<'_> {
         }
     }
 
-    fn check_matching_clause_type(&mut self, ctx: &CompletionContext) {
+    fn check_matching_clause_type(&mut self, ctx: &TreesitterContext) {
         let clause_type = match ctx.wrapping_clause_type.as_ref() {
             None => return,
             Some(ct) => ct,
@@ -135,14 +137,16 @@ impl CompletionScore<'_> {
         }
     }
 
-    fn check_matching_wrapping_node(&mut self, ctx: &CompletionContext) {
+    fn check_matching_wrapping_node(&mut self, ctx: &TreesitterContext) {
         let wrapping_node = match ctx.wrapping_node_kind.as_ref() {
             None => return,
             Some(wn) => wn,
         };
 
         let has_mentioned_schema = ctx.schema_or_alias_name.is_some();
-        let has_node_text = ctx.get_node_under_cursor_content().is_some();
+        let has_node_text = ctx
+            .get_node_under_cursor_content()
+            .is_some_and(|txt| !sanitization::is_sanitized_token(txt.as_str()));
 
         self.score += match self.data {
             CompletionRelevanceData::Table(_) => match wrapping_node {
@@ -170,7 +174,7 @@ impl CompletionScore<'_> {
         }
     }
 
-    fn check_is_invocation(&mut self, ctx: &CompletionContext) {
+    fn check_is_invocation(&mut self, ctx: &TreesitterContext) {
         self.score += match self.data {
             CompletionRelevanceData::Function(_) if ctx.is_invocation => 30,
             CompletionRelevanceData::Function(_) if !ctx.is_invocation => -10,
@@ -179,7 +183,7 @@ impl CompletionScore<'_> {
         };
     }
 
-    fn check_matches_schema(&mut self, ctx: &CompletionContext) {
+    fn check_matches_schema(&mut self, ctx: &TreesitterContext) {
         let schema_name = match ctx.schema_or_alias_name.as_ref() {
             None => return,
             Some(n) => n,
@@ -228,7 +232,7 @@ impl CompletionScore<'_> {
         }
     }
 
-    fn check_relations_in_stmt(&mut self, ctx: &CompletionContext) {
+    fn check_relations_in_stmt(&mut self, ctx: &TreesitterContext) {
         match self.data {
             CompletionRelevanceData::Table(_) | CompletionRelevanceData::Function(_) => return,
             _ => {}
@@ -312,7 +316,7 @@ impl CompletionScore<'_> {
         }
     }
 
-    fn check_columns_in_stmt(&mut self, ctx: &CompletionContext) {
+    fn check_columns_in_stmt(&mut self, ctx: &TreesitterContext) {
         if let CompletionRelevanceData::Column(column) = self.data {
             /*
              * Columns can be mentioned in one of two ways:
diff --git a/crates/pgt_completions/src/sanitization.rs b/crates/pgt_completions/src/sanitization.rs
index bf4d98160..155256c8a 100644
--- a/crates/pgt_completions/src/sanitization.rs
+++ b/crates/pgt_completions/src/sanitization.rs
@@ -23,6 +23,10 @@ pub(crate) fn remove_sanitized_token(it: &str) -> String {
     it.replace(SANITIZED_TOKEN, "")
 }
 
+pub(crate) fn is_sanitized_token(txt: &str) -> bool {
+    txt == SANITIZED_TOKEN
+}
+
 #[derive(PartialEq, Eq, Debug)]
 pub(crate) enum NodeText {
     Replaced,
@@ -118,10 +122,6 @@ where
             tree: Cow::Borrowed(params.tree),
         }
     }
-
-    pub fn is_sanitized_token(txt: &str) -> bool {
-        txt == SANITIZED_TOKEN
-    }
 }
 
 /// Checks if the cursor is positioned inbetween two SQL nodes.
diff --git a/crates/pgt_completions/src/test_helper.rs b/crates/pgt_completions/src/test_helper.rs
index 1bd5229ca..e6c347614 100644
--- a/crates/pgt_completions/src/test_helper.rs
+++ b/crates/pgt_completions/src/test_helper.rs
@@ -1,40 +1,12 @@
-use std::fmt::Display;
-
 use pgt_schema_cache::SchemaCache;
+use pgt_test_utils::QueryWithCursorPosition;
 use sqlx::{Executor, PgPool};
 
 use crate::{CompletionItem, CompletionItemKind, CompletionParams, complete};
 
-pub static CURSOR_POS: char = '€';
-
-#[derive(Clone)]
-pub struct InputQuery {
-    sql: String,
-    position: usize,
-}
-
-impl From<&str> for InputQuery {
-    fn from(value: &str) -> Self {
-        let position = value
-            .find(CURSOR_POS)
-            .expect("Insert Cursor Position into your Query.");
-
-        InputQuery {
-            sql: value.replace(CURSOR_POS, "").trim().to_string(),
-            position,
-        }
-    }
-}
-
-impl Display for InputQuery {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{}", self.sql)
-    }
-}
-
 pub(crate) async fn get_test_deps(
     setup: Option<&str>,
-    input: InputQuery,
+    input: QueryWithCursorPosition,
     test_db: &PgPool,
 ) -> (tree_sitter::Tree, pgt_schema_cache::SchemaCache) {
     if let Some(setup) = setup {
@@ -63,7 +35,7 @@ pub(crate) async fn get_test_deps(
 #[allow(dead_code)]
 pub(crate) async fn test_against_connection_string(
     conn_str: &str,
-    input: InputQuery,
+    input: QueryWithCursorPosition,
 ) -> (tree_sitter::Tree, pgt_schema_cache::SchemaCache) {
     let pool = sqlx::PgPool::connect(conn_str)
         .await
@@ -83,16 +55,12 @@ pub(crate) async fn test_against_connection_string(
     (tree, schema_cache)
 }
 
-pub(crate) fn get_text_and_position(q: InputQuery) -> (usize, String) {
-    (q.position, q.sql)
-}
-
 pub(crate) fn get_test_params<'a>(
     tree: &'a tree_sitter::Tree,
     schema_cache: &'a pgt_schema_cache::SchemaCache,
-    sql: InputQuery,
+    sql: QueryWithCursorPosition,
 ) -> CompletionParams<'a> {
-    let (position, text) = get_text_and_position(sql);
+    let (position, text) = sql.get_text_and_position();
 
     CompletionParams {
         position: (position as u32).into(),
@@ -102,46 +70,6 @@ pub(crate) fn get_test_params<'a>(
     }
 }
 
-#[cfg(test)]
-mod tests {
-    use crate::test_helper::CURSOR_POS;
-
-    use super::InputQuery;
-
-    #[test]
-    fn input_query_should_extract_correct_position() {
-        struct TestCase {
-            query: String,
-            expected_pos: usize,
-            expected_sql_len: usize,
-        }
-
-        let cases = vec![
-            TestCase {
-                query: format!("select * from{}", CURSOR_POS),
-                expected_pos: 13,
-                expected_sql_len: 13,
-            },
-            TestCase {
-                query: format!("{}select * from", CURSOR_POS),
-                expected_pos: 0,
-                expected_sql_len: 13,
-            },
-            TestCase {
-                query: format!("select {} from", CURSOR_POS),
-                expected_pos: 7,
-                expected_sql_len: 12,
-            },
-        ];
-
-        for case in cases {
-            let query = InputQuery::from(case.query.as_str());
-            assert_eq!(query.position, case.expected_pos);
-            assert_eq!(query.sql.len(), case.expected_sql_len);
-        }
-    }
-}
-
 #[derive(Debug, PartialEq, Eq)]
 pub(crate) enum CompletionAssertion {
     Label(String),
diff --git a/crates/pgt_diagnostics/src/serde.rs b/crates/pgt_diagnostics/src/serde.rs
index 334bd4e9e..57ed3e280 100644
--- a/crates/pgt_diagnostics/src/serde.rs
+++ b/crates/pgt_diagnostics/src/serde.rs
@@ -164,6 +164,7 @@ impl From<super::Location<'_>> for Location {
 #[serde(rename_all = "camelCase")]
 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
 #[cfg_attr(test, derive(Eq, PartialEq))]
+
 struct Advices {
     advices: Vec<Advice>,
 }
@@ -250,7 +251,7 @@ impl super::Advices for Advices {
 #[derive(Clone, Debug, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
-#[cfg_attr(test, derive(Eq, PartialEq))]
+#[cfg_attr(test, derive(PartialEq, Eq))]
 enum Advice {
     Log(LogCategory, MarkupBuf),
     List(Vec<MarkupBuf>),
diff --git a/crates/pgt_diagnostics_categories/src/categories.rs b/crates/pgt_diagnostics_categories/src/categories.rs
index d5ce48d7e..14df90b9e 100644
--- a/crates/pgt_diagnostics_categories/src/categories.rs
+++ b/crates/pgt_diagnostics_categories/src/categories.rs
@@ -13,12 +13,12 @@
 // must be between `define_categories! {\n` and `\n    ;\n`.
 
 define_categories! {
-    "lint/safety/addingRequiredField": "https://pglt.dev/linter/rules/adding-required-field",
-    "lint/safety/banDropColumn": "https://pglt.dev/linter/rules/ban-drop-column",
-    "lint/safety/banDropDatabase": "https://pgtools.dev/linter/rules/ban-drop-database",
-    "lint/safety/banDropNotNull": "https://pglt.dev/linter/rules/ban-drop-not-null",
-    "lint/safety/banDropTable": "https://pglt.dev/linter/rules/ban-drop-table",
-    "lint/safety/banTruncateCascade": "https://pgtools.dev/linter/rules/ban-truncate-cascade",
+    "lint/safety/addingRequiredField": "https://pgtools.dev/latest/rules/adding-required-field",
+    "lint/safety/banDropColumn": "https://pgtools.dev/latest/rules/ban-drop-column",
+    "lint/safety/banDropDatabase": "https://pgtools.dev/latest/rules/ban-drop-database",
+    "lint/safety/banDropNotNull": "https://pgtools.dev/latest/rules/ban-drop-not-null",
+    "lint/safety/banDropTable": "https://pgtools.dev/latest/rules/ban-drop-table",
+    "lint/safety/banTruncateCascade": "https://pgtools.dev/latest/rules/ban-truncate-cascade",
     // end lint rules
     ;
     // General categories
@@ -32,6 +32,7 @@ define_categories! {
     "flags/invalid",
     "project",
     "typecheck",
+    "plpgsql_check",
     "internalError/panic",
     "syntax",
     "dummy",
diff --git a/crates/pgt_lsp/src/handlers/text_document.rs b/crates/pgt_lsp/src/handlers/text_document.rs
index cc2efb4b3..1c5a9a115 100644
--- a/crates/pgt_lsp/src/handlers/text_document.rs
+++ b/crates/pgt_lsp/src/handlers/text_document.rs
@@ -1,12 +1,10 @@
-use crate::{
-    diagnostics::LspError, documents::Document, session::Session, utils::apply_document_changes,
-};
+use crate::{documents::Document, session::Session, utils::apply_document_changes};
 use anyhow::Result;
 use pgt_workspace::workspace::{
     ChangeFileParams, CloseFileParams, GetFileContentParams, OpenFileParams,
 };
 use tower_lsp::lsp_types;
-use tracing::error;
+use tracing::{error, field};
 
 /// Handler for `textDocument/didOpen` LSP notification
 #[tracing::instrument(level = "debug", skip(session), err)]
@@ -36,12 +34,12 @@ pub(crate) async fn did_open(
     Ok(())
 }
 
-// Handler for `textDocument/didChange` LSP notification
-#[tracing::instrument(level = "debug", skip(session), err)]
+/// Handler for `textDocument/didChange` LSP notification
+#[tracing::instrument(level = "debug", skip_all, fields(url = field::display(&params.text_document.uri), version = params.text_document.version), err)]
 pub(crate) async fn did_change(
     session: &Session,
     params: lsp_types::DidChangeTextDocumentParams,
-) -> Result<(), LspError> {
+) -> Result<()> {
     let url = params.text_document.uri;
     let version = params.text_document.version;
 
@@ -56,7 +54,7 @@ pub(crate) async fn did_change(
     let text = apply_document_changes(
         session.position_encoding(),
         old_text,
-        &params.content_changes,
+        params.content_changes,
     );
 
     tracing::trace!("new document: {:?}", text);
diff --git a/crates/pgt_lsp/src/utils.rs b/crates/pgt_lsp/src/utils.rs
index 92059b66c..8361cf08e 100644
--- a/crates/pgt_lsp/src/utils.rs
+++ b/crates/pgt_lsp/src/utils.rs
@@ -1,5 +1,6 @@
+use crate::adapters::from_lsp::text_range;
 use crate::adapters::line_index::LineIndex;
-use crate::adapters::{PositionEncoding, from_lsp, to_lsp};
+use crate::adapters::{PositionEncoding, to_lsp};
 use anyhow::{Context, Result, ensure};
 use pgt_console::MarkupBuf;
 use pgt_console::fmt::Termcolor;
@@ -10,8 +11,8 @@ use pgt_text_size::{TextRange, TextSize};
 use std::any::Any;
 use std::borrow::Cow;
 use std::fmt::{Debug, Display};
-use std::io;
 use std::ops::{Add, Range};
+use std::{io, mem};
 use tower_lsp::jsonrpc::Error as LspError;
 use tower_lsp::lsp_types;
 use tower_lsp::lsp_types::{self as lsp, CodeDescription, Url};
@@ -183,7 +184,7 @@ pub(crate) fn panic_to_lsp_error(err: Box<dyn Any + Send>) -> LspError {
 pub(crate) fn apply_document_changes(
     position_encoding: PositionEncoding,
     current_content: String,
-    content_changes: &[lsp_types::TextDocumentContentChangeEvent],
+    mut content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
 ) -> String {
     // Skip to the last full document change, as it invalidates all previous changes anyways.
     let mut start = content_changes
@@ -192,12 +193,12 @@ pub(crate) fn apply_document_changes(
         .position(|change| change.range.is_none())
         .map_or(0, |idx| content_changes.len() - idx - 1);
 
-    let mut text: String = match content_changes.get(start) {
+    let mut text: String = match content_changes.get_mut(start) {
         // peek at the first content change as an optimization
         Some(lsp_types::TextDocumentContentChangeEvent {
             range: None, text, ..
         }) => {
-            let text = text.clone();
+            let text = mem::take(text);
             start += 1;
 
             // The only change is a full document update
@@ -225,12 +226,11 @@ pub(crate) fn apply_document_changes(
                 line_index = LineIndex::new(&text);
             }
             index_valid = range.start.line;
-            if let Ok(range) = from_lsp::text_range(&line_index, range, position_encoding) {
+            if let Ok(range) = text_range(&line_index, range, position_encoding) {
                 text.replace_range(Range::<usize>::from(range), &change.text);
             }
         }
     }
-
     text
 }
 
diff --git a/crates/pgt_lsp/tests/server.rs b/crates/pgt_lsp/tests/server.rs
index 176868f55..63953590b 100644
--- a/crates/pgt_lsp/tests/server.rs
+++ b/crates/pgt_lsp/tests/server.rs
@@ -1773,3 +1773,490 @@ $$;
 
     Ok(())
 }
+
+#[tokio::test]
+async fn test_crash_on_delete_character() -> Result<()> {
+    let factory = ServerFactory::default();
+    let (service, client) = factory.create(None).into_inner();
+    let (stream, sink) = client.split();
+    let mut server = Server::new(service);
+
+    let (sender, _) = channel(CHANNEL_BUFFER_SIZE);
+    let reader = tokio::spawn(client_handler(stream, sink, sender));
+
+    server.initialize().await?;
+    server.initialized().await?;
+
+    // Open document with initial CREATE INDEX statement - exactly as in log
+    let initial_content = "\n\n\n\nCREATE INDEX \"idx_analytics_read_ratio\" ON \"public\".\"message\" USING \"btree\" (\"inbox_id\", \"timestamp\") INCLUDE (\"status\") WHERE (\"is_inbound\" = false);\n";
+
+    server.open_document(initial_content).await?;
+
+    // Add a space after false (position 148 from the log)
+    server
+        .change_document(
+            3,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 148,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 148,
+                    },
+                }),
+                range_length: Some(0),
+                text: " ".to_string(),
+            }],
+        )
+        .await?;
+
+    // Follow the exact sequence from the logfile
+    // Type character by character in exact order
+
+    // Version 4: "a" at 149
+    server
+        .change_document(
+            4,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 149,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 149,
+                    },
+                }),
+                range_length: Some(0),
+                text: "a".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 5: "n" at 150
+    server
+        .change_document(
+            5,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 150,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 150,
+                    },
+                }),
+                range_length: Some(0),
+                text: "n".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 6: "d" at 151
+    server
+        .change_document(
+            6,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 151,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 151,
+                    },
+                }),
+                range_length: Some(0),
+                text: "d".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 7: " " at 152
+    server
+        .change_document(
+            7,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 152,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 152,
+                    },
+                }),
+                range_length: Some(0),
+                text: " ".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 8: "c" at 153
+    server
+        .change_document(
+            8,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 153,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 153,
+                    },
+                }),
+                range_length: Some(0),
+                text: "c".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 10: "h" at 154 and "a" at 155 (two changes in one version)
+    server
+        .change_document(
+            10,
+            vec![
+                TextDocumentContentChangeEvent {
+                    range: Some(Range {
+                        start: Position {
+                            line: 4,
+                            character: 154,
+                        },
+                        end: Position {
+                            line: 4,
+                            character: 154,
+                        },
+                    }),
+                    range_length: Some(0),
+                    text: "h".to_string(),
+                },
+                TextDocumentContentChangeEvent {
+                    range: Some(Range {
+                        start: Position {
+                            line: 4,
+                            character: 155,
+                        },
+                        end: Position {
+                            line: 4,
+                            character: 155,
+                        },
+                    }),
+                    range_length: Some(0),
+                    text: "a".to_string(),
+                },
+            ],
+        )
+        .await?;
+
+    // Version 11: "n" at 156
+    server
+        .change_document(
+            11,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 156,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 156,
+                    },
+                }),
+                range_length: Some(0),
+                text: "n".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 12: "n" at 157
+    server
+        .change_document(
+            12,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 157,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 157,
+                    },
+                }),
+                range_length: Some(0),
+                text: "n".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 13: "e" at 158
+    server
+        .change_document(
+            13,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 158,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 158,
+                    },
+                }),
+                range_length: Some(0),
+                text: "e".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 14: "l" at 159
+    server
+        .change_document(
+            14,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 159,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 159,
+                    },
+                }),
+                range_length: Some(0),
+                text: "l".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 15: "_" at 160
+    server
+        .change_document(
+            15,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 160,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 160,
+                    },
+                }),
+                range_length: Some(0),
+                text: "_".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 16: "t" at 161
+    server
+        .change_document(
+            16,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 161,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 161,
+                    },
+                }),
+                range_length: Some(0),
+                text: "t".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 17: "y" at 162
+    server
+        .change_document(
+            17,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 162,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 162,
+                    },
+                }),
+                range_length: Some(0),
+                text: "y".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 18: "p" at 163
+    server
+        .change_document(
+            18,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 163,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 163,
+                    },
+                }),
+                range_length: Some(0),
+                text: "p".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 19: "e" at 164
+    server
+        .change_document(
+            19,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 164,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 164,
+                    },
+                }),
+                range_length: Some(0),
+                text: "e".to_string(),
+            }],
+        )
+        .await?;
+
+    // Version 20: " " at 165
+    server
+        .change_document(
+            20,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 165,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 165,
+                    },
+                }),
+                range_length: Some(0),
+                text: " ".to_string(),
+            }],
+        )
+        .await?;
+
+    // Now we should have: "WHERE ("is_inbound" = false and channel_type )"
+
+    // Version 21: Paste the problematic text with double single quotes
+    server
+        .change_document(
+            21,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 166,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 166,
+                    },
+                }),
+                range_length: Some(0),
+                text: "channel_type not in (''postal'', ''sms'')".to_string(),
+            }],
+        )
+        .await?;
+
+    // Delete "channel_type"
+    server
+        .change_document(
+            22,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 166,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 178,
+                    },
+                }),
+                range_length: Some(12),
+                text: "".to_string(),
+            }],
+        )
+        .await?;
+
+    // Delete one more character
+    server
+        .change_document(
+            23,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 166,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 167,
+                    },
+                }),
+                range_length: Some(1),
+                text: "".to_string(),
+            }],
+        )
+        .await?;
+
+    // This final delete should trigger the panic
+    let result = server
+        .change_document(
+            24,
+            vec![TextDocumentContentChangeEvent {
+                range: Some(Range {
+                    start: Position {
+                        line: 4,
+                        character: 175,
+                    },
+                    end: Position {
+                        line: 4,
+                        character: 176,
+                    },
+                }),
+                range_length: Some(1),
+                text: "".to_string(),
+            }],
+        )
+        .await;
+
+    assert!(result.is_ok());
+
+    reader.abort();
+
+    Ok(())
+}
diff --git a/crates/pgt_plpgsql_check/Cargo.toml b/crates/pgt_plpgsql_check/Cargo.toml
new file mode 100644
index 000000000..75d1a52b3
--- /dev/null
+++ b/crates/pgt_plpgsql_check/Cargo.toml
@@ -0,0 +1,30 @@
+[package]
+authors.workspace    = true
+categories.workspace = true
+description          = "<DESCRIPTION>"
+edition.workspace    = true
+homepage.workspace   = true
+keywords.workspace   = true
+license.workspace    = true
+name                 = "pgt_plpgsql_check"
+repository.workspace = true
+version              = "0.0.0"
+
+
+[dependencies]
+pgt_console      = { workspace = true }
+pgt_diagnostics  = { workspace = true }
+pgt_query        = { workspace = true }
+pgt_query_ext    = { workspace = true }
+pgt_schema_cache = { workspace = true }
+pgt_text_size    = { workspace = true }
+regex            = { workspace = true }
+serde            = { workspace = true }
+serde_json       = { workspace = true }
+sqlx             = { workspace = true }
+tree-sitter      = { workspace = true }
+
+[dev-dependencies]
+pgt_test_utils = { workspace = true }
+
+[lib]
diff --git a/crates/pgt_plpgsql_check/src/diagnostics.rs b/crates/pgt_plpgsql_check/src/diagnostics.rs
new file mode 100644
index 000000000..a0daec13d
--- /dev/null
+++ b/crates/pgt_plpgsql_check/src/diagnostics.rs
@@ -0,0 +1,245 @@
+use std::io;
+
+use pgt_console::markup;
+use pgt_diagnostics::{Advices, Diagnostic, LogCategory, MessageAndDescription, Severity, Visit};
+use pgt_text_size::TextRange;
+
+use crate::{PlpgSqlCheckIssue, PlpgSqlCheckResult};
+
+/// Find the first occurrence of target text that is not within string literals
+fn find_text_outside_strings(text: &str, target: &str) -> Option<usize> {
+    let text_lower = text.to_lowercase();
+    let target_lower = target.to_lowercase();
+    let mut in_string = false;
+    let mut quote_char = '\0';
+    let bytes = text_lower.as_bytes();
+    let mut i = 0;
+
+    while i < bytes.len() {
+        let ch = bytes[i] as char;
+
+        if !in_string {
+            // Check if we're starting a string literal
+            if ch == '\'' || ch == '"' {
+                in_string = true;
+                quote_char = ch;
+            } else {
+                // Check if we found our target at this position
+                if text_lower[i..].starts_with(&target_lower) {
+                    // Check if this is a complete word (not part of another identifier)
+                    let is_word_start =
+                        i == 0 || !bytes[i - 1].is_ascii_alphanumeric() && bytes[i - 1] != b'_';
+                    let target_end = i + target_lower.len();
+                    let is_word_end = target_end >= bytes.len()
+                        || (!bytes[target_end].is_ascii_alphanumeric()
+                            && bytes[target_end] != b'_');
+
+                    if is_word_start && is_word_end {
+                        return Some(i);
+                    }
+                }
+            }
+        } else {
+            // We're inside a string literal
+            if ch == quote_char {
+                // Check if it's escaped (look for double quotes/apostrophes)
+                if i + 1 < bytes.len() && bytes[i + 1] as char == quote_char {
+                    // Skip the escaped quote
+                    i += 1;
+                } else {
+                    // End of string literal
+                    in_string = false;
+                    quote_char = '\0';
+                }
+            }
+        }
+
+        i += 1;
+    }
+
+    None
+}
+
+/// A specialized diagnostic for plpgsql_check.
+#[derive(Clone, Debug, Diagnostic)]
+#[diagnostic(category = "plpgsql_check")]
+pub struct PlPgSqlCheckDiagnostic {
+    #[location(span)]
+    pub span: Option<TextRange>,
+    #[description]
+    #[message]
+    pub message: MessageAndDescription,
+    #[advice]
+    pub advices: PlPgSqlCheckAdvices,
+    #[severity]
+    pub severity: Severity,
+}
+
+#[derive(Debug, Clone)]
+pub struct PlPgSqlCheckAdvices {
+    pub code: Option<String>,
+    /// the relation (table or view) where the issue was found, if applicable
+    /// only applicable for trigger functions
+    pub relation: Option<String>,
+}
+
+impl Advices for PlPgSqlCheckAdvices {
+    fn record(&self, visitor: &mut dyn Visit) -> io::Result<()> {
+        // Show the error code if available
+        if let Some(code) = &self.code {
+            visitor.record_log(
+                LogCategory::Error,
+                &markup! { "SQL State: " <Emphasis>{code}</Emphasis> },
+            )?;
+        }
+
+        // Show relation information if available
+        if let Some(relation) = &self.relation {
+            visitor.record_log(
+                LogCategory::Info,
+                &markup! { "Relation: " <Emphasis>{relation}</Emphasis> },
+            )?;
+        }
+
+        Ok(())
+    }
+}
+
+/// Convert plpgsql_check results into diagnostics with optional relation info for triggers
+pub fn create_diagnostics_from_check_result(
+    result: &PlpgSqlCheckResult,
+    fn_body: &str,
+    offset: usize,
+    relation: Option<String>,
+) -> Vec<PlPgSqlCheckDiagnostic> {
+    result
+        .issues
+        .iter()
+        .map(|issue| {
+            let severity = match issue.level.as_str() {
+                "error" => Severity::Error,
+                "warning" => Severity::Warning,
+                "notice" => Severity::Hint,
+                _ => Severity::Information,
+            };
+
+            PlPgSqlCheckDiagnostic {
+                message: issue.message.clone().into(),
+                severity,
+                span: resolve_span(issue, fn_body, offset),
+                advices: PlPgSqlCheckAdvices {
+                    code: issue.sql_state.clone(),
+                    relation: relation.clone(),
+                },
+            }
+        })
+        .collect()
+}
+
+fn resolve_span(issue: &PlpgSqlCheckIssue, fn_body: &str, offset: usize) -> Option<TextRange> {
+    let stmt = match issue.statement.as_ref() {
+        Some(s) => s,
+        None => {
+            return Some(TextRange::new(
+                (offset as u32).into(),
+                ((offset + fn_body.len()) as u32).into(),
+            ));
+        }
+    };
+
+    let line_number = stmt
+        .line_number
+        .parse::<usize>()
+        .expect("Expected line number to be a valid usize");
+
+    let text = &stmt.text;
+
+    // calculate the offset to the target line
+    let line_offset: usize = fn_body
+        .lines()
+        .take(line_number - 1)
+        .map(|line| line.len() + 1) // +1 for newline
+        .sum();
+
+    // find the position within the target line
+    let line = fn_body.lines().nth(line_number - 1)?;
+    let start = line
+        .to_lowercase()
+        .find(&text.to_lowercase())
+        .unwrap_or_else(|| {
+            line.char_indices()
+                .find_map(|(i, c)| if !c.is_whitespace() { Some(i) } else { None })
+                .unwrap_or(0)
+        });
+
+    let stmt_offset = line_offset + start;
+
+    if let Some(q) = &issue.query {
+        // first find the query within the fn body *after* stmt_offset, ignoring string literals
+        let query_start = find_text_outside_strings(&fn_body[stmt_offset..], &q.text)
+            .map(|pos| pos + stmt_offset);
+
+        // the position is *within* the query text
+        let pos = q
+            .position
+            .parse::<usize>()
+            .expect("Expected query position to be a valid usize")
+            - 1; // -1 because the position is 1-based
+
+        let start = query_start? + pos;
+
+        // the range of the diagnostics is the token that `pos` is on
+        // Find the end of the current token by looking for whitespace or SQL delimiters
+        let remaining = &fn_body[start..];
+        let end = remaining
+            .char_indices()
+            .find(|(_, c)| {
+                c.is_whitespace() || matches!(c, ',' | ';' | ')' | '(' | '=' | '<' | '>')
+            })
+            .map(|(i, _c)| {
+                i // just the token end, don't include delimiters
+            })
+            .unwrap_or(remaining.len());
+
+        return Some(TextRange::new(
+            ((offset + start) as u32).into(),
+            ((offset + start + end) as u32).into(),
+        ));
+    }
+
+    // if no query is present, the end range covers
+    // - if text is "IF" or "ELSIF", then until the next "THEN"
+    // - TODO: check "LOOP", "CASE", "WHILE", "EXPECTION" and others
+    // - else: until the next semicolon or end of line
+
+    if text.to_uppercase() == "IF" || text.to_uppercase() == "ELSIF" {
+        // Find the position of the next "THEN" after the statement
+        let remaining = &fn_body[stmt_offset..];
+        if let Some(then_pos) = remaining.to_uppercase().find("THEN") {
+            let end = then_pos + "THEN".len();
+            return Some(TextRange::new(
+                ((offset + stmt_offset) as u32).into(),
+                ((offset + stmt_offset + end) as u32).into(),
+            ));
+        }
+    }
+
+    // if no specific end is found, use the next semicolon or the end of the line
+    let remaining = &fn_body[stmt_offset..];
+    let end = remaining
+        .char_indices()
+        .find(|(_, c)| matches!(c, ';' | '\n' | '\r'))
+        .map(|(i, c)| {
+            if c == ';' {
+                i + 1 // include the semicolon
+            } else {
+                i // just the end of the line
+            }
+        })
+        .unwrap_or(remaining.len());
+
+    Some(TextRange::new(
+        ((offset + stmt_offset) as u32).into(),
+        ((offset + stmt_offset + end) as u32).into(),
+    ))
+}
diff --git a/crates/pgt_plpgsql_check/src/lib.rs b/crates/pgt_plpgsql_check/src/lib.rs
new file mode 100644
index 000000000..05e2f5709
--- /dev/null
+++ b/crates/pgt_plpgsql_check/src/lib.rs
@@ -0,0 +1,794 @@
+mod diagnostics;
+
+pub use diagnostics::PlPgSqlCheckDiagnostic;
+use diagnostics::create_diagnostics_from_check_result;
+use pgt_query::protobuf::CreateFunctionStmt;
+use regex::Regex;
+use serde::Deserialize;
+pub use sqlx::postgres::PgSeverity;
+use sqlx::{Acquire, PgPool, Postgres, Transaction};
+
+#[derive(Debug)]
+pub struct PlPgSqlCheckParams<'a> {
+    pub conn: &'a PgPool,
+    pub sql: &'a str,
+    pub ast: &'a pgt_query::NodeEnum,
+    pub schema_cache: &'a pgt_schema_cache::SchemaCache,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct PlpgSqlCheckResult {
+    pub function: String,
+    pub issues: Vec<PlpgSqlCheckIssue>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct PlpgSqlCheckIssue {
+    pub level: String,
+    pub message: String,
+    pub statement: Option<Statement>,
+    pub query: Option<Query>,
+    #[serde(rename = "sqlState")]
+    pub sql_state: Option<String>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Statement {
+    #[serde(rename = "lineNumber")]
+    pub line_number: String,
+    pub text: String,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Query {
+    pub position: String,
+    pub text: String,
+}
+
+/// check if the given node is a plpgsql function that should be checked
+fn should_check_function<'a>(
+    ast: &'a pgt_query::NodeEnum,
+    schema_cache: &pgt_schema_cache::SchemaCache,
+) -> Option<&'a CreateFunctionStmt> {
+    let create_fn = match ast {
+        pgt_query::NodeEnum::CreateFunctionStmt(stmt) => stmt,
+        _ => return None,
+    };
+
+    if pgt_query_ext::utils::find_option_value(create_fn, "language") != Some("plpgsql".to_string())
+    {
+        return None;
+    }
+
+    if !schema_cache
+        .extensions
+        .iter()
+        .any(|e| e.name == "plpgsql_check")
+    {
+        return None;
+    }
+
+    Some(create_fn)
+}
+
+/// check if a function is a trigger function
+fn is_trigger_function(create_fn: &CreateFunctionStmt) -> bool {
+    create_fn
+        .return_type
+        .as_ref()
+        .map(|n| {
+            matches!(
+                pgt_query_ext::utils::parse_name(&n.names),
+                Some((None, name)) if name == "trigger"
+            )
+        })
+        .unwrap_or(false)
+}
+
+/// build the function identifier string used by plpgsql_check
+fn build_function_identifier(
+    create_fn: &CreateFunctionStmt,
+    fn_schema: &Option<String>,
+    fn_name: &str,
+) -> String {
+    let args = create_fn
+        .parameters
+        .iter()
+        .filter_map(|arg| {
+            let node = match &arg.node {
+                Some(pgt_query::NodeEnum::FunctionParameter(n)) => n,
+                _ => return None,
+            };
+            let type_name_node = node.arg_type.as_ref()?;
+            let type_name = match pgt_query_ext::utils::parse_name(&type_name_node.names) {
+                Some((schema, name)) => match schema {
+                    Some(s) => format!("{}.{}", s, name),
+                    None => name,
+                },
+                None => return None,
+            };
+
+            if !type_name_node.array_bounds.is_empty() {
+                Some(format!("{}[]", type_name))
+            } else {
+                Some(type_name)
+            }
+        })
+        .collect::<Vec<_>>();
+
+    let fn_qualified_name = match fn_schema {
+        Some(schema) => format!("{}.{}", schema, fn_name),
+        None => fn_name.to_string(),
+    };
+
+    if args.is_empty() {
+        fn_qualified_name
+    } else {
+        format!("{}({})", fn_qualified_name, args.join(", "))
+    }
+}
+
+pub async fn check_plpgsql(
+    params: PlPgSqlCheckParams<'_>,
+) -> Result<Vec<PlPgSqlCheckDiagnostic>, sqlx::Error> {
+    let create_fn = match should_check_function(params.ast, params.schema_cache) {
+        Some(stmt) => stmt,
+        None => return Ok(vec![]),
+    };
+
+    let (fn_schema, fn_name) = match pgt_query_ext::utils::parse_name(&create_fn.funcname) {
+        Some(n) => n,
+        None => return Ok(vec![]),
+    };
+
+    let fn_identifier = build_function_identifier(create_fn, &fn_schema, &fn_name);
+
+    let fn_body = pgt_query_ext::utils::find_option_value(create_fn, "as")
+        .ok_or_else(|| sqlx::Error::Protocol("Failed to find function body".to_string()))?;
+    let offset = params
+        .sql
+        .find(&fn_body)
+        .ok_or_else(|| sqlx::Error::Protocol("Failed to find function body in SQL".to_string()))?;
+    let is_trigger = is_trigger_function(create_fn);
+
+    let mut conn = params.conn.acquire().await?;
+    conn.close_on_drop();
+
+    let mut tx: Transaction<'_, Postgres> = conn.begin().await?;
+
+    // disable function body checking to rely on plpgsql_check
+    sqlx::query("SET LOCAL check_function_bodies = off")
+        .execute(&mut *tx)
+        .await?;
+
+    // make sure we run with "or replace"
+    let sql_with_replace = if !create_fn.replace {
+        let re = Regex::new(r"(?i)\bCREATE\s+FUNCTION\b").unwrap();
+        re.replace(params.sql, "CREATE OR REPLACE FUNCTION")
+            .to_string()
+    } else {
+        params.sql.to_string()
+    };
+
+    // create the function - this should always succeed
+    sqlx::query(&sql_with_replace).execute(&mut *tx).await?;
+
+    // run plpgsql_check and collect results with their relations
+    let results_with_relations: Vec<(String, Option<String>)> = if is_trigger {
+        let mut results = Vec::new();
+
+        for trigger in params.schema_cache.triggers.iter() {
+            if trigger.proc_name == fn_name
+                && (fn_schema.is_none() || fn_schema.as_deref() == Some(&trigger.proc_schema))
+            {
+                let relation = format!("{}.{}", trigger.table_schema, trigger.table_name);
+
+                let result: Option<String> = sqlx::query_scalar(&format!(
+                    "select plpgsql_check_function('{}', '{}', format := 'json')",
+                    fn_identifier, relation
+                ))
+                .fetch_optional(&mut *tx)
+                .await?
+                .flatten();
+
+                if let Some(result) = result {
+                    results.push((result, Some(relation)));
+                }
+            }
+        }
+
+        results
+    } else {
+        let result: Option<String> = sqlx::query_scalar(&format!(
+            "select plpgsql_check_function('{}', format := 'json')",
+            fn_identifier
+        ))
+        .fetch_optional(&mut *tx)
+        .await?
+        .flatten();
+
+        if let Some(result) = result {
+            vec![(result, None)]
+        } else {
+            vec![]
+        }
+    };
+
+    tx.rollback().await?;
+
+    // Parse results and create diagnostics
+    let mut diagnostics = Vec::new();
+    for (result_json, relation) in results_with_relations {
+        let check_result: PlpgSqlCheckResult = serde_json::from_str(&result_json).map_err(|e| {
+            sqlx::Error::Protocol(format!("Failed to parse plpgsql_check result: {}", e))
+        })?;
+
+        let mut result_diagnostics =
+            create_diagnostics_from_check_result(&check_result, &fn_body, offset, relation);
+        diagnostics.append(&mut result_diagnostics);
+    }
+
+    Ok(diagnostics)
+}
+
+#[cfg(all(test, not(target_os = "windows")))]
+mod tests {
+    use sqlx::{Executor, PgPool};
+
+    /// Test helper to run plpgsql_check and return diagnostics with span text
+    async fn run_plpgsql_check_test(
+        test_db: &PgPool,
+        setup_sql: &str,
+        create_fn_sql: &str,
+    ) -> Result<(Vec<super::PlPgSqlCheckDiagnostic>, Vec<Option<String>>), Box<dyn std::error::Error>>
+    {
+        test_db.execute(setup_sql).await?;
+
+        let ast = pgt_query::parse(create_fn_sql)?
+            .into_root()
+            .ok_or("Failed to parse SQL root")?;
+        let schema_cache = pgt_schema_cache::SchemaCache::load(test_db).await?;
+
+        let diagnostics = super::check_plpgsql(super::PlPgSqlCheckParams {
+            conn: test_db,
+            sql: create_fn_sql,
+            ast: &ast,
+            schema_cache: &schema_cache,
+        })
+        .await?;
+
+        let span_texts = diagnostics
+            .iter()
+            .map(|diag| {
+                diag.span.as_ref().map(|s| {
+                    let start = usize::from(s.start());
+                    let end = usize::from(s.end());
+                    create_fn_sql[start..end].to_string()
+                })
+            })
+            .collect();
+
+        Ok((diagnostics, span_texts))
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_if_expr(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            CREATE TABLE t1(a int, b int);
+        "#;
+
+        let create_fn_sql = r#"
+            CREATE OR REPLACE FUNCTION public.f1()
+            RETURNS void
+            LANGUAGE plpgsql
+            AS $function$
+            declare r t1 := (select t1 from t1 where a = 1);
+            BEGIN
+              if r.c is null or
+                 true is false
+                then -- there is bug - table t1 missing "c" column
+                RAISE NOTICE 'c is null';
+              end if;
+            END;
+            $function$;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert_eq!(diagnostics.len(), 1);
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert_eq!(
+            span_texts[0].as_deref(),
+            Some("if r.c is null or\n                 true is false\n                then")
+        );
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_missing_var(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            CREATE TABLE t1(a int, b int);
+        "#;
+
+        let create_fn_sql = r#"
+            CREATE OR REPLACE FUNCTION public.f1()
+            RETURNS void
+            LANGUAGE plpgsql
+            AS $function$
+            BEGIN
+                SELECT 1 from t1 where a = v_c;
+            END;
+            $function$;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+        assert_eq!(diagnostics.len(), 1);
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert_eq!(span_texts[0].as_deref(), Some("v_c"));
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_missing_col_if_stmt(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            CREATE TABLE t1(a int, b int);
+        "#;
+
+        let create_fn_sql = r#"
+            CREATE OR REPLACE FUNCTION public.f1()
+            RETURNS void
+            LANGUAGE plpgsql
+            AS $function$
+            BEGIN
+              if (select c from t1 where id = 1) is null then -- there is bug - table t1 missing "c" column
+                RAISE NOTICE 'c is null';
+              end if;
+            END;
+            $function$;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+        assert_eq!(diagnostics.len(), 1);
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert_eq!(span_texts[0].as_deref(), Some("c"));
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            CREATE TABLE t1(a int, b int);
+        "#;
+
+        let create_fn_sql = r#"
+            CREATE OR REPLACE FUNCTION public.f1()
+            RETURNS void
+            LANGUAGE plpgsql
+            AS $function$
+            DECLARE r record;
+            BEGIN
+              FOR r IN SELECT * FROM t1
+              LOOP
+                RAISE NOTICE '%', r.c; -- there is bug - table t1 missing "c" column
+              END LOOP;
+            END;
+            $function$;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert_eq!(diagnostics.len(), 1);
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert_eq!(span_texts[0].as_deref(), Some("RAISE NOTICE '%', r.c;"));
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_stacked_diagnostics(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+        "#;
+
+        let create_fn_sql = r#"
+            create or replace function fxtest()
+            returns void as $$
+            declare
+              v_sqlstate text;
+              v_message text;
+              v_context text;
+            begin
+              get stacked diagnostics
+                v_sqlstate = returned_sqlstate,
+                v_message = message_text,
+                v_context = pg_exception_context;
+            end;
+            $$ language plpgsql;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert!(!diagnostics.is_empty());
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert_eq!(span_texts[0].as_deref(), Some("get stacked diagnostics"));
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_constant_refcursor(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+            create table rc_test(a int);
+        "#;
+
+        let create_fn_sql = r#"
+            create function return_constant_refcursor() returns refcursor as $$
+            declare
+                rc constant refcursor;
+            begin
+                open rc for select a from rc_test;
+                return rc;
+            end
+            $$ language plpgsql;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert!(!diagnostics.is_empty());
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert_eq!(
+            span_texts[0].as_deref(),
+            Some("open rc for select a from rc_test;")
+        );
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_constant_assignment(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            create procedure p1(a int, out b int)
+            as $$
+            begin
+              b := a + 10;
+            end;
+            $$ language plpgsql;
+        "#;
+
+        let create_fn_sql = r#"
+            create function f1()
+            returns void as $$
+            declare b constant int;
+            begin
+              call p1(10, b);
+            end;
+            $$ language plpgsql;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert!(!diagnostics.is_empty());
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert_eq!(span_texts[0].as_deref(), Some("call p1(10, b);"));
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_missing_procedure(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+        "#;
+
+        let create_fn_sql = r#"
+            create function f1()
+            returns void as $$
+            declare b constant int;
+            begin
+              call p1(10, b);
+            end;
+            $$ language plpgsql;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert!(!diagnostics.is_empty());
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert_eq!(span_texts[0].as_deref(), Some("p1"));
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_dml_in_stable_function(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+            create table t1(a int, b int);
+        "#;
+
+        let create_fn_sql = r#"
+            create function f1()
+            returns void as $$
+            begin
+              if false then
+                insert into t1 values(10,20);
+                update t1 set a = 10;
+                delete from t1;
+              end if;
+            end;
+            $$ language plpgsql stable;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert_eq!(diagnostics.len(), 1);
+        assert!(span_texts[0].is_some());
+
+        assert_eq!(diagnostics[0].advices.code.as_deref(), Some("0A000"));
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_record_field_assignment(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            create function g1() returns table(a int, b int) as $$
+            begin
+              return query select 1, 2;
+            end;
+            $$ language plpgsql;
+        "#;
+
+        let create_fn_sql = r#"
+            create or replace function f1()
+            returns void as $$
+            declare r record;
+            begin
+              for r in select * from g1()
+              loop
+                r.c := 20;
+              end loop;
+            end;
+            $$ language plpgsql;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert!(!diagnostics.is_empty());
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert!(span_texts[0].is_some());
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_trigger_basic(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            CREATE TABLE users(
+                id serial primary key,
+                name text not null,
+                email text
+            );
+
+            CREATE OR REPLACE FUNCTION public.log_user_changes()
+            RETURNS trigger
+            LANGUAGE plpgsql
+            AS $function$
+            BEGIN
+                -- Intentional error: referencing non-existent column
+                INSERT INTO audit_log(table_name, changed_id, old_email, new_email)
+                VALUES ('users', NEW.id, OLD.email, NEW.email);
+                RETURN NEW;
+            END;
+            $function$;
+
+            CREATE TRIGGER trg_users_audit
+                AFTER UPDATE ON users
+                FOR EACH ROW
+                EXECUTE FUNCTION public.log_user_changes();
+        "#;
+
+        let create_fn_sql = r#"
+            CREATE OR REPLACE FUNCTION public.log_user_changes()
+            RETURNS trigger
+            LANGUAGE plpgsql
+            AS $function$
+            BEGIN
+                -- Intentional error: referencing non-existent column
+                INSERT INTO audit_log(table_name, changed_id, old_email, new_email)
+                VALUES ('users', NEW.id, OLD.email, NEW.email);
+                RETURN NEW;
+            END;
+            $function$;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert!(!diagnostics.is_empty());
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert!(diagnostics[0].advices.relation.is_some());
+        assert_eq!(
+            diagnostics[0].advices.relation.as_deref(),
+            Some("public.users")
+        );
+        assert_eq!(span_texts[0].as_deref(), Some("audit_log"));
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_trigger_missing_column(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            CREATE TABLE products(
+                id serial primary key,
+                name text not null,
+                price numeric(10,2)
+            );
+
+            CREATE OR REPLACE FUNCTION public.validate_product()
+            RETURNS trigger
+            LANGUAGE plpgsql
+            AS $function$
+            BEGIN
+                -- Error: referencing non-existent column
+                IF NEW.category IS NULL THEN
+                    RAISE EXCEPTION 'Category is required';
+                END IF;
+                RETURN NEW;
+            END;
+            $function$;
+
+            CREATE TRIGGER trg_product_validation
+                BEFORE INSERT OR UPDATE ON products
+                FOR EACH ROW
+                EXECUTE FUNCTION public.validate_product();
+        "#;
+
+        let create_fn_sql = r#"
+            CREATE OR REPLACE FUNCTION public.validate_product()
+            RETURNS trigger
+            LANGUAGE plpgsql
+            AS $function$
+            BEGIN
+                -- Error: referencing non-existent column
+                IF NEW.category IS NULL THEN
+                    RAISE EXCEPTION 'Category is required';
+                END IF;
+                RETURN NEW;
+            END;
+            $function$;
+        "#;
+
+        let (diagnostics, span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert!(!diagnostics.is_empty());
+        assert!(matches!(
+            diagnostics[0].severity,
+            pgt_diagnostics::Severity::Error
+        ));
+        assert!(span_texts[0].as_deref().unwrap().contains("category"));
+        assert_eq!(
+            diagnostics[0].advices.relation.as_deref(),
+            Some("public.products")
+        );
+    }
+
+    #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+    async fn test_plpgsql_check_trigger_multiple_tables(test_db: PgPool) {
+        let setup = r#"
+            create extension if not exists plpgsql_check;
+
+            CREATE TABLE table_a(
+                id serial primary key,
+                name text
+            );
+
+            CREATE TABLE table_b(
+                id serial primary key,
+                description text
+            );
+
+            CREATE OR REPLACE FUNCTION public.generic_audit()
+            RETURNS trigger
+            LANGUAGE plpgsql
+            AS $function$
+            BEGIN
+                -- Error: referencing column that doesn't exist in both tables
+                INSERT INTO audit_log(table_name, record_id, old_status)
+                VALUES (TG_TABLE_NAME, NEW.id, OLD.status);
+                RETURN NEW;
+            END;
+            $function$;
+
+            CREATE TRIGGER trg_audit_a
+                AFTER UPDATE ON table_a
+                FOR EACH ROW
+                EXECUTE FUNCTION public.generic_audit();
+
+            CREATE TRIGGER trg_audit_b
+                AFTER UPDATE ON table_b
+                FOR EACH ROW
+                EXECUTE FUNCTION public.generic_audit();
+        "#;
+
+        let create_fn_sql = r#"
+            CREATE OR REPLACE FUNCTION public.generic_audit()
+            RETURNS trigger
+            LANGUAGE plpgsql
+            AS $function$
+            BEGIN
+                -- Error: referencing column that doesn't exist in both tables
+                INSERT INTO audit_log(table_name, record_id, old_status)
+                VALUES (TG_TABLE_NAME, NEW.id, OLD.status);
+                RETURN NEW;
+            END;
+            $function$;
+        "#;
+
+        let (diagnostics, _span_texts) = run_plpgsql_check_test(&test_db, setup, create_fn_sql)
+            .await
+            .expect("Failed to run plpgsql_check test");
+
+        assert!(!diagnostics.is_empty());
+        assert!(diagnostics.len() >= 2);
+
+        let relations: Vec<_> = diagnostics
+            .iter()
+            .filter_map(|d| d.advices.relation.as_ref())
+            .collect();
+        assert!(relations.contains(&&"public.table_a".to_string()));
+        assert!(relations.contains(&&"public.table_b".to_string()));
+    }
+}
diff --git a/crates/pgt_query/Cargo.toml b/crates/pgt_query/Cargo.toml
new file mode 100644
index 000000000..881b1b800
--- /dev/null
+++ b/crates/pgt_query/Cargo.toml
@@ -0,0 +1,36 @@
+[package]
+authors.workspace    = true
+categories.workspace = true
+description          = "<DESCRIPTION>"
+edition.workspace    = true
+homepage.workspace   = true
+keywords.workspace   = true
+license.workspace    = true
+name                 = "pgt_query"
+repository.workspace = true
+version              = "0.0.0"
+
+[dependencies]
+prost     = { workspace = true }
+thiserror = { workspace = true }
+
+pgt_query_macros = { workspace = true }
+
+
+[features]
+default     = ["postgres-17"]
+postgres-15 = []
+postgres-16 = []
+postgres-17 = []
+
+[build-dependencies]
+bindgen     = "0.72.0"
+cc          = "1.0.83"
+clippy      = { version = "0.0.302", optional = true }
+fs_extra    = "1.2.0"
+glob        = "0.3.1"
+prost-build = "0.13.5"
+which       = "6.0.0"
+
+[dev-dependencies]
+easy-parallel = "3.2.0"
diff --git a/crates/pgt_query/build.rs b/crates/pgt_query/build.rs
new file mode 100644
index 000000000..292b3af28
--- /dev/null
+++ b/crates/pgt_query/build.rs
@@ -0,0 +1,260 @@
+#![cfg_attr(feature = "clippy", feature(plugin))]
+#![cfg_attr(feature = "clippy", plugin(clippy))]
+
+use fs_extra::dir::CopyOptions;
+use glob::glob;
+use std::env;
+use std::path::PathBuf;
+use std::process::Command;
+
+static LIBRARY_NAME: &str = "pg_query";
+static LIBPG_QUERY_REPO: &str = "https://github.com/pganalyze/libpg_query.git";
+fn get_libpg_query_tag() -> &'static str {
+    #[cfg(feature = "postgres-15")]
+    return "15-5.3.0";
+    #[cfg(feature = "postgres-16")]
+    return "16-6.1.0";
+    #[cfg(feature = "postgres-17")]
+    return "17-6.1.0";
+}
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    let libpg_query_tag = get_libpg_query_tag();
+    let out_dir = PathBuf::from(env::var("OUT_DIR")?);
+    let vendor_dir = out_dir.join("vendor");
+    let libpg_query_dir = vendor_dir.join("libpg_query").join(libpg_query_tag);
+    let stamp_file = libpg_query_dir.join(".stamp");
+
+    let src_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?).join("src");
+    let target = env::var("TARGET").unwrap();
+    let is_emscripten = target.contains("emscripten");
+
+    // Configure cargo through stdout
+    println!("cargo:rustc-link-search=native={}", out_dir.display());
+    println!("cargo:rustc-link-lib=static={LIBRARY_NAME}");
+
+    // Clone libpg_query if not already present
+    if !stamp_file.exists() {
+        println!("cargo:warning=Cloning libpg_query {}", libpg_query_tag);
+
+        // Create vendor directory
+        std::fs::create_dir_all(&vendor_dir)?;
+
+        // Clone the repository with partial clone for faster download
+        let status = Command::new("git")
+            .args([
+                "clone",
+                "--filter=blob:none",
+                "--depth",
+                "1",
+                "--branch",
+                libpg_query_tag,
+                LIBPG_QUERY_REPO,
+                libpg_query_dir.to_str().unwrap(),
+            ])
+            .status()?;
+
+        if !status.success() {
+            return Err("Failed to clone libpg_query".into());
+        }
+
+        // Create stamp file
+        std::fs::File::create(&stamp_file)?;
+    }
+
+    // Tell cargo to rerun if the stamp file is deleted
+    println!("cargo:rerun-if-changed={}", stamp_file.display());
+
+    // Copy necessary files to OUT_DIR for compilation
+    let out_header_path = out_dir.join(LIBRARY_NAME).with_extension("h");
+    let out_protobuf_path = out_dir.join("protobuf");
+
+    let source_paths = vec![
+        libpg_query_dir.join(LIBRARY_NAME).with_extension("h"),
+        libpg_query_dir.join("Makefile"),
+        libpg_query_dir.join("src"),
+        libpg_query_dir.join("protobuf"),
+        libpg_query_dir.join("vendor"),
+    ];
+
+    let copy_options = CopyOptions {
+        overwrite: true,
+        ..CopyOptions::default()
+    };
+
+    fs_extra::copy_items(&source_paths, &out_dir, &copy_options)?;
+
+    // Compile the C library.
+    let mut build = cc::Build::new();
+
+    // Configure for Emscripten if needed
+    if is_emscripten {
+        // Use emcc as the compiler instead of gcc/clang
+        build.compiler("emcc");
+        // Use emar as the archiver instead of ar
+        build.archiver("emar");
+        // Note: We don't add WASM-specific flags here as this creates a static library
+        // The final linking flags should be added when building the final WASM module
+    }
+
+    build
+        .files(
+            glob(out_dir.join("src/*.c").to_str().unwrap())
+                .unwrap()
+                .map(|p| p.unwrap()),
+        )
+        .files(
+            glob(out_dir.join("src/postgres/*.c").to_str().unwrap())
+                .unwrap()
+                .map(|p| p.unwrap()),
+        )
+        .file(out_dir.join("vendor/protobuf-c/protobuf-c.c"))
+        .file(out_dir.join("vendor/xxhash/xxhash.c"))
+        .file(out_dir.join("protobuf/pg_query.pb-c.c"))
+        .include(out_dir.join("."))
+        .include(out_dir.join("./vendor"))
+        .include(out_dir.join("./src/postgres/include"))
+        .include(out_dir.join("./src/include"))
+        .warnings(false); // Avoid unnecessary warnings, as they are already considered as part of libpg_query development
+    if env::var("PROFILE").unwrap() == "debug" || env::var("DEBUG").unwrap() == "1" {
+        build.define("USE_ASSERT_CHECKING", None);
+    }
+    if target.contains("windows") && !is_emscripten {
+        build.include(out_dir.join("./src/postgres/include/port/win32"));
+        if target.contains("msvc") {
+            build.include(out_dir.join("./src/postgres/include/port/win32_msvc"));
+        }
+    }
+    build.compile(LIBRARY_NAME);
+
+    // Generate bindings for Rust
+    let mut bindgen_builder = bindgen::Builder::default()
+        .header(out_header_path.to_str().ok_or("Invalid header path")?)
+        // Allowlist only the functions we need
+        .allowlist_function("pg_query_parse_protobuf")
+        .allowlist_function("pg_query_scan")
+        .allowlist_function("pg_query_deparse_protobuf")
+        .allowlist_function("pg_query_normalize")
+        .allowlist_function("pg_query_fingerprint")
+        .allowlist_function("pg_query_split_with_parser")
+        .allowlist_function("pg_query_split_with_scanner")
+        .allowlist_function("pg_query_parse_plpgsql")
+        .allowlist_function("pg_query_free_protobuf_parse_result")
+        .allowlist_function("pg_query_free_scan_result")
+        .allowlist_function("pg_query_free_deparse_result")
+        .allowlist_function("pg_query_free_normalize_result")
+        .allowlist_function("pg_query_free_fingerprint_result")
+        .allowlist_function("pg_query_free_split_result")
+        .allowlist_function("pg_query_free_plpgsql_parse_result")
+        // Allowlist the types used by these functions
+        .allowlist_type("PgQueryProtobufParseResult")
+        .allowlist_type("PgQueryScanResult")
+        .allowlist_type("PgQueryError")
+        .allowlist_type("PgQueryProtobuf")
+        .allowlist_type("PgQueryDeparseResult")
+        .allowlist_type("PgQueryNormalizeResult")
+        .allowlist_type("PgQueryFingerprintResult")
+        .allowlist_type("PgQuerySplitResult")
+        .allowlist_type("PgQuerySplitStmt")
+        // Also generate bindings for size_t since it's used in PgQueryProtobuf
+        .allowlist_type("size_t")
+        .allowlist_var("PG_VERSION_NUM");
+
+    // Configure bindgen for Emscripten target
+    if is_emscripten {
+        // Tell bindgen to generate bindings for the wasm32 target
+        bindgen_builder = bindgen_builder.clang_arg("--target=wasm32-unknown-emscripten");
+
+        // Add emscripten sysroot includes
+        // First try to use EMSDK environment variable (set in CI and when sourcing emsdk_env.sh)
+        if let Ok(emsdk) = env::var("EMSDK") {
+            bindgen_builder = bindgen_builder.clang_arg(format!(
+                "-I{}/upstream/emscripten/cache/sysroot/include",
+                emsdk
+            ));
+        } else {
+            // Fallback to the default path if EMSDK is not set
+            bindgen_builder =
+                bindgen_builder.clang_arg("-I/emsdk/upstream/emscripten/cache/sysroot/include");
+        }
+
+        // Ensure we have the basic C standard library headers
+        bindgen_builder = bindgen_builder.clang_arg("-D__EMSCRIPTEN__");
+
+        // Use environment variable if set (from our justfile)
+        if let Ok(extra_args) = env::var("BINDGEN_EXTRA_CLANG_ARGS") {
+            for arg in extra_args.split_whitespace() {
+                bindgen_builder = bindgen_builder.clang_arg(arg);
+            }
+        }
+    }
+
+    let bindings = bindgen_builder
+        .generate()
+        .map_err(|_| "Unable to generate bindings")?;
+
+    let bindings_path = out_dir.join("bindings.rs");
+    bindings.write_to_file(&bindings_path)?;
+
+    // For WASM/emscripten builds, manually add the function declarations
+    // since bindgen sometimes misses them due to preprocessor conditions
+    if is_emscripten {
+        let mut bindings_content = std::fs::read_to_string(&bindings_path)?;
+
+        // Check if we need to add the extern "C" block
+        if !bindings_content.contains("extern \"C\"") {
+            bindings_content.push_str("\nextern \"C\" {\n");
+            bindings_content.push_str("    pub fn pg_query_scan(input: *const ::std::os::raw::c_char) -> PgQueryScanResult;\n");
+            bindings_content.push_str("    pub fn pg_query_parse_protobuf(input: *const ::std::os::raw::c_char) -> PgQueryProtobufParseResult;\n");
+            bindings_content.push_str("    pub fn pg_query_parse_plpgsql(input: *const ::std::os::raw::c_char) -> PgQueryPlpgsqlParseResult;\n");
+            bindings_content.push_str("    pub fn pg_query_deparse_protobuf(protobuf: PgQueryProtobuf) -> PgQueryDeparseResult;\n");
+            bindings_content.push_str("    pub fn pg_query_normalize(input: *const ::std::os::raw::c_char) -> PgQueryNormalizeResult;\n");
+            bindings_content.push_str("    pub fn pg_query_fingerprint(input: *const ::std::os::raw::c_char) -> PgQueryFingerprintResult;\n");
+            bindings_content.push_str("    pub fn pg_query_split_with_parser(input: *const ::std::os::raw::c_char) -> PgQuerySplitResult;\n");
+            bindings_content.push_str("    pub fn pg_query_split_with_scanner(input: *const ::std::os::raw::c_char) -> PgQuerySplitResult;\n");
+            bindings_content
+                .push_str("    pub fn pg_query_free_scan_result(result: PgQueryScanResult);\n");
+            bindings_content.push_str("    pub fn pg_query_free_protobuf_parse_result(result: PgQueryProtobufParseResult);\n");
+            bindings_content.push_str("    pub fn pg_query_free_plpgsql_parse_result(result: PgQueryPlpgsqlParseResult);\n");
+            bindings_content.push_str(
+                "    pub fn pg_query_free_deparse_result(result: PgQueryDeparseResult);\n",
+            );
+            bindings_content.push_str(
+                "    pub fn pg_query_free_normalize_result(result: PgQueryNormalizeResult);\n",
+            );
+            bindings_content.push_str(
+                "    pub fn pg_query_free_fingerprint_result(result: PgQueryFingerprintResult);\n",
+            );
+            bindings_content
+                .push_str("    pub fn pg_query_free_split_result(result: PgQuerySplitResult);\n");
+            bindings_content.push_str("}\n");
+
+            std::fs::write(&bindings_path, bindings_content)?;
+        }
+    }
+
+    let protoc_exists = Command::new("protoc").arg("--version").status().is_ok();
+    if protoc_exists {
+        println!("generating protobuf bindings");
+        // HACK: Set OUT_DIR to src/ so that the generated protobuf file is copied to src/protobuf.rs
+        unsafe {
+            env::set_var("OUT_DIR", &src_dir);
+        }
+
+        prost_build::compile_protos(
+            &[&out_protobuf_path.join(LIBRARY_NAME).with_extension("proto")],
+            &[&out_protobuf_path],
+        )?;
+
+        std::fs::rename(src_dir.join("pg_query.rs"), src_dir.join("protobuf.rs"))?;
+
+        // Reset OUT_DIR to the original value
+        unsafe {
+            env::set_var("OUT_DIR", &out_dir);
+        }
+    } else {
+        println!("skipping protobuf generation");
+    }
+
+    Ok(())
+}
diff --git a/crates/pgt_query/examples/api_example.rs b/crates/pgt_query/examples/api_example.rs
new file mode 100644
index 000000000..d71b1c0fe
--- /dev/null
+++ b/crates/pgt_query/examples/api_example.rs
@@ -0,0 +1,42 @@
+use pgt_query::{NodeRef, parse};
+
+fn main() {
+    let mut result = parse("SELECT * FROM users WHERE id IN (SELECT id FROM admins)").unwrap();
+
+    // Immutable access
+    {
+        let stmts = result.stmts();
+        let stmt = stmts.first().unwrap();
+
+        // nodes() returns a Vec<NodeRef>
+        let all_nodes = stmt.nodes();
+        println!("Total nodes in AST: {}", all_nodes.len());
+
+        // Can still iterate with iter()
+        let select_count = stmt
+            .iter()
+            .filter(|n| matches!(n, NodeRef::SelectStmt(_)))
+            .count();
+        println!("Number of SELECT statements: {}", select_count);
+    }
+
+    // Mutable access - no cloning needed!
+    {
+        let mut stmts = result.stmts_mut();
+        if let Some(stmt) = stmts.first_mut() {
+            // Now we can iterate mutably without cloning
+            for mut_node in stmt.iter_mut() {
+                // Modify nodes here if needed
+                if let pgt_query::NodeMut::SelectStmt(_select) = mut_node {
+                    println!("Found a SELECT statement to modify");
+                    // You can modify _select here
+                }
+            }
+        }
+    }
+
+    // Alternative: using root_mut() for single statement queries
+    if let Some(root) = result.root_mut() {
+        println!("Root node type: {:?}", std::mem::discriminant(root));
+    }
+}
diff --git a/crates/pgt_query/src/deparse.rs b/crates/pgt_query/src/deparse.rs
new file mode 100644
index 000000000..91f3d4503
--- /dev/null
+++ b/crates/pgt_query/src/deparse.rs
@@ -0,0 +1,93 @@
+use std::ffi::CStr;
+use std::os::raw::c_char;
+
+use crate::bindings::*;
+use crate::error::*;
+use crate::protobuf;
+
+use prost::Message;
+
+/// Converts a parsed tree back into a string.
+///
+/// # Example
+///
+/// ```rust
+/// use pgt_query::{parse, NodeEnum, NodeRef};
+///
+/// let result = parse("INSERT INTO other (name) SELECT name FROM contacts");
+/// let result = result.unwrap();
+/// let stmts = result.stmts();
+/// let insert = stmts.first().unwrap();
+/// assert!(matches!(insert, NodeEnum::InsertStmt(_)));
+/// let select = insert.iter().find(|n| matches!(n, NodeRef::SelectStmt(_))).unwrap();
+///
+/// // The entire parse result can be deparsed:
+/// assert_eq!(result.deparse().unwrap(), "INSERT INTO other (name) SELECT name FROM contacts");
+/// // Or an individual node can be deparsed:
+/// assert_eq!(insert.deparse().unwrap(), "INSERT INTO other (name) SELECT name FROM contacts");
+/// assert_eq!(select.deparse().unwrap(), "SELECT name FROM contacts");
+/// ```
+///
+/// Note that this function will panic if called on a node not defined in `deparseStmt`
+pub fn deparse(protobuf: &protobuf::ParseResult) -> Result<String> {
+    let buffer = protobuf.encode_to_vec();
+    let len = buffer.len();
+    let data = buffer.as_ptr() as *const c_char as *mut c_char;
+    let protobuf = PgQueryProtobuf { data, len };
+    let result = unsafe { pg_query_deparse_protobuf(protobuf) };
+
+    let deparse_result = if !result.error.is_null() {
+        let message = unsafe { CStr::from_ptr((*result.error).message) }
+            .to_string_lossy()
+            .to_string();
+        Err(Error::Parse(message))
+    } else {
+        let query = unsafe { CStr::from_ptr(result.query) }
+            .to_string_lossy()
+            .to_string();
+        Ok(query)
+    };
+
+    unsafe { pg_query_free_deparse_result(result) };
+    deparse_result
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::parse;
+
+    fn assert_deparse(input: &str, output: &str) {
+        let result = parse(input).unwrap();
+        assert_eq!(result.deparse().unwrap(), output);
+    }
+
+    #[test]
+    fn it_deparses_select() {
+        let query = "SELECT a AS b FROM x WHERE y = 5 AND z = y";
+        assert_deparse(query, query);
+    }
+
+    #[test]
+    fn it_deparses_select_with_empty_target_list() {
+        let query = "SELECT FROM x WHERE y = 5 AND z = y";
+        assert_deparse(query, query);
+    }
+
+    #[test]
+    fn it_deparses_select_with_schema() {
+        let query = "SELECT a AS b FROM public.x WHERE y = 5 AND z = y";
+        assert_deparse(query, query);
+    }
+
+    #[test]
+    fn it_deparses_select_with_distinct() {
+        let query = "SELECT DISTINCT a, b, * FROM c WHERE d = e";
+        assert_deparse(query, query);
+    }
+
+    #[test]
+    fn it_deparses_select_with_distinct_on() {
+        let query = "SELECT DISTINCT ON (a) a, b FROM c";
+        assert_deparse(query, query);
+    }
+}
diff --git a/crates/pgt_query/src/error.rs b/crates/pgt_query/src/error.rs
new file mode 100644
index 000000000..50845b44c
--- /dev/null
+++ b/crates/pgt_query/src/error.rs
@@ -0,0 +1,23 @@
+use thiserror::Error;
+
+/// Error structure representing the basic error scenarios for `pg_query`.
+#[derive(Debug, Error, Eq, PartialEq)]
+pub enum Error {
+    #[error("Invalid statement format: {0}")]
+    Conversion(#[from] std::ffi::NulError),
+    #[error("Error decoding result: {0}")]
+    Decode(#[from] prost::DecodeError),
+    #[error("Invalid statement: {0}")]
+    Parse(String),
+    #[error("Error parsing JSON: {0}")]
+    InvalidJson(String),
+    #[error("Invalid pointer")]
+    InvalidPointer,
+    #[error("Error scanning: {0}")]
+    Scan(String),
+    #[error("Error splitting: {0}")]
+    Split(String),
+}
+
+/// Convenient Result alias for returning `pg_query::Error`.
+pub type Result<T> = core::result::Result<T, Error>;
diff --git a/crates/pgt_query/src/fingerprint.rs b/crates/pgt_query/src/fingerprint.rs
new file mode 100644
index 000000000..127b6ca6a
--- /dev/null
+++ b/crates/pgt_query/src/fingerprint.rs
@@ -0,0 +1,359 @@
+use std::ffi::{CStr, CString};
+
+use crate::bindings::*;
+use crate::error::*;
+
+/// Represents the resulting fingerprint containing both the raw integer form as well as the
+/// corresponding 16 character hex value.
+pub struct Fingerprint {
+    pub value: u64,
+    pub hex: String,
+}
+
+/// Fingerprints the given SQL statement. Useful for comparing parse trees across different implementations
+/// of `libpg_query`.
+///
+/// # Example
+///
+/// ```rust
+/// let result = pgt_query::fingerprint("SELECT * FROM contacts WHERE name='Paul'");
+/// assert!(result.is_ok());
+/// let result = result.unwrap();
+/// assert_eq!(result.hex, "0e2581a461ece536");
+/// ```
+pub fn fingerprint(statement: &str) -> Result<Fingerprint> {
+    let input = CString::new(statement)?;
+    let result = unsafe { pg_query_fingerprint(input.as_ptr()) };
+    let fingerprint = if !result.error.is_null() {
+        let message = unsafe { CStr::from_ptr((*result.error).message) }
+            .to_string_lossy()
+            .to_string();
+        Err(Error::Parse(message))
+    } else {
+        let hex = unsafe { CStr::from_ptr(result.fingerprint_str) };
+        Ok(Fingerprint {
+            value: result.fingerprint,
+            hex: hex.to_string_lossy().to_string(),
+        })
+    };
+    unsafe { pg_query_free_fingerprint_result(result) };
+    fingerprint
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::{Error, fingerprint};
+
+    #[test]
+    fn it_can_fingerprint_a_simple_statement() {
+        let result =
+            fingerprint("SELECT * FROM contacts.person WHERE id IN (1, 2, 3, 4);").unwrap();
+        assert_eq!(result.hex, "643d2a3c294ab8a7");
+    }
+
+    #[test]
+    fn it_will_error_on_invalid_input() {
+        let error = fingerprint("CREATE RANDOM ix_test ON contacts.person;")
+            .err()
+            .unwrap();
+        assert_eq!(
+            error,
+            Error::Parse("syntax error at or near \"RANDOM\"".into())
+        );
+    }
+
+    #[test]
+    fn it_works_for_multi_statement_queries() {
+        let q1 = "SET x=$1; SELECT A";
+        let q2 = "SET x=$1; SELECT a";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        let q1 = "SET x=$1; SELECT A";
+        let q2 = "SELECT a";
+        assert_ne!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+    }
+
+    #[test]
+    fn it_ignores_aliases() {
+        let q1 = "SELECT a AS b";
+        let q2 = "SELECT a AS c";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        let q1 = "SELECT a";
+        let q2 = "SELECT a AS c";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        let q1 = "SELECT * FROM a AS b";
+        let q2 = "SELECT * FROM a AS c";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        let q1 = "SELECT * FROM a";
+        let q2 = "SELECT * FROM a AS c";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        let q1 = "SELECT * FROM (SELECT * FROM x AS y) AS a";
+        let q2 = "SELECT * FROM (SELECT * FROM x AS z) AS b";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        let q1 = "SELECT a AS b UNION SELECT x AS y";
+        let q2 = "SELECT a AS c UNION SELECT x AS z";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+    }
+
+    #[test]
+    fn it_ignores_param_references() {
+        let q1 = "SELECT $1";
+        let q2 = "SELECT $2";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+    }
+
+    #[test]
+    fn it_ignores_select_target_list_ordering() {
+        let q1 = "SELECT a, b FROM x";
+        let q2 = "SELECT b, a FROM x";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+        let q1 = "SELECT $1, b FROM x";
+        let q2 = "SELECT b, $1 FROM x";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+        let q1 = "SELECT $1, $2, b FROM x";
+        let q2 = "SELECT $1, b, $2 FROM x";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        // Testing uniqueness
+        let q1 = "SELECT a, c FROM x";
+        let q2 = "SELECT b, a FROM x";
+        assert_ne!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+        let q1 = "SELECT b FROM x";
+        let q2 = "SELECT b, a FROM x";
+        assert_ne!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+    }
+
+    #[test]
+    fn it_ignores_insert_col_ordering() {
+        let q1 = "INSERT INTO test (a, b) VALUES ($1, $2)";
+        let q2 = "INSERT INTO test (b, a) VALUES ($1, $2)";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        // Testing uniqueness
+        let q1 = "INSERT INTO test (a, c) VALUES ($1, $2)";
+        let q2 = "INSERT INTO test (b, a) VALUES ($1, $2)";
+        assert_ne!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+        let q1 = "INSERT INTO test (b) VALUES ($1, $2)";
+        let q2 = "INSERT INTO test (b, a) VALUES ($1, $2)";
+        assert_ne!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+    }
+
+    #[test]
+    fn it_ignores_in_list_size() {
+        let q1 = "SELECT * FROM x WHERE y IN ($1, $2, $3)";
+        let q2 = "SELECT * FROM x WHERE y IN ($1)";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+
+        let q1 = "SELECT * FROM x WHERE y IN ( $1::uuid, $2::uuid, $3::uuid )";
+        let q2 = "SELECT * FROM x WHERE y IN ( $1::uuid )";
+        assert_eq!(fingerprint(q1).unwrap().hex, fingerprint(q2).unwrap().hex);
+    }
+
+    #[test]
+    fn it_works() {
+        let result = fingerprint("SELECT 1").unwrap();
+        assert_eq!(result.hex, "50fde20626009aba");
+
+        let result = fingerprint("SELECT 2").unwrap();
+        assert_eq!(result.hex, "50fde20626009aba");
+
+        let result = fingerprint("SELECT $1").unwrap();
+        assert_eq!(result.hex, "50fde20626009aba");
+
+        let result = fingerprint("SELECT 1; SELECT a FROM b").unwrap();
+        assert_eq!(result.hex, "3efa3b10d558d06d");
+
+        let result = fingerprint("SELECT COUNT(DISTINCT id), * FROM targets WHERE something IS NOT NULL AND elsewhere::interval < now()").unwrap();
+        assert_eq!(result.hex, "26b6553101185d22");
+
+        let result = fingerprint("INSERT INTO test (a, b) VALUES ($1, $2)").unwrap();
+        assert_eq!(result.hex, "51e63b8083b48bdd");
+
+        let result = fingerprint("INSERT INTO test (b, a) VALUES ($1, $2)").unwrap();
+        assert_eq!(result.hex, "51e63b8083b48bdd");
+
+        let result = fingerprint(
+        "INSERT INTO test (a, b) VALUES (ARRAY[$1, $2, $3, $4], $5::timestamptz), (ARRAY[$6, $7, $8, $9], $10::timestamptz), ($11, $12::timestamptz)",
+    )
+    .unwrap();
+        assert_eq!(result.hex, "4dfdd5260cac5acf");
+
+        let result = fingerprint("SELECT b AS x, a AS y FROM z").unwrap();
+        assert_eq!(result.hex, "1a8bf5d7614de3a5");
+
+        let result = fingerprint("SELECT * FROM x WHERE y = $1").unwrap();
+        assert_eq!(result.hex, "4ff39426bd074231");
+
+        let result = fingerprint("SELECT * FROM x WHERE y = ANY ($1)").unwrap();
+        assert_eq!(result.hex, "4ff39426bd074231");
+
+        let result = fingerprint("SELECT * FROM x WHERE y IN ($1)").unwrap();
+        assert_eq!(result.hex, "4ff39426bd074231");
+
+        let result = fingerprint("SELECT * FROM x WHERE y IN ($1, $2, $3)").unwrap();
+        assert_eq!(result.hex, "4ff39426bd074231");
+
+        let result = fingerprint("SELECT * FROM x WHERE y IN ( $1::uuid )").unwrap();
+        assert_eq!(result.hex, "4ff39426bd074231");
+
+        let result =
+            fingerprint("SELECT * FROM x WHERE y IN ( $1::uuid, $2::uuid, $3::uuid )").unwrap();
+        assert_eq!(result.hex, "4ff39426bd074231");
+
+        let result = fingerprint("PREPARE a123 AS SELECT a").unwrap();
+        assert_eq!(result.hex, "9b5e6ead8be993e8");
+
+        let result = fingerprint("EXECUTE a123").unwrap();
+        assert_eq!(result.hex, "44ef1d2beabd53e8");
+
+        let result = fingerprint("DEALLOCATE a123").unwrap();
+        assert_eq!(result.hex, "d8a65a814fbc5f95");
+
+        let result = fingerprint("DEALLOCATE ALL").unwrap();
+        assert_eq!(result.hex, "2debfb8745df64a7");
+
+        let result = fingerprint("EXPLAIN ANALYZE SELECT a").unwrap();
+        assert_eq!(result.hex, "82845c1b5c6102e5");
+
+        let result =
+            fingerprint("WITH a AS (SELECT * FROM x WHERE x.y = $1 AND x.z = 1) SELECT * FROM a")
+                .unwrap();
+        assert_eq!(result.hex, "6831e38bbb3dd18c");
+
+        let result =
+        fingerprint("CREATE TABLE types (a float(2), b float(49), c NUMERIC(2, 3), d character(4), e char(5), f varchar(6), g character varying(7))")
+            .unwrap();
+        assert_eq!(result.hex, "008d6ba4aa0f4c6e");
+
+        let result =
+        fingerprint("CREATE VIEW view_a (a, b) AS WITH RECURSIVE view_a (a, b) AS (SELECT * FROM a(1)) SELECT \"a\", \"b\" FROM \"view_a\"").unwrap();
+        assert_eq!(result.hex, "c6ef6b9f498feda4");
+
+        let result = fingerprint("VACUUM FULL my_table").unwrap();
+        assert_eq!(result.hex, "fdf2f4127644f4d8");
+
+        let result = fingerprint("SELECT * FROM x AS a, y AS b").unwrap();
+        assert_eq!(result.hex, "4e9acae841dae228");
+
+        let result = fingerprint("SELECT * FROM y AS a, x AS b").unwrap();
+        assert_eq!(result.hex, "4e9acae841dae228");
+
+        let result = fingerprint("SELECT x AS a, y AS b FROM x").unwrap();
+        assert_eq!(result.hex, "65dff5f5e9a643ad");
+
+        let result = fingerprint("SELECT y AS a, x AS b FROM x").unwrap();
+        assert_eq!(result.hex, "65dff5f5e9a643ad");
+
+        let result = fingerprint("SELECT x, y FROM z").unwrap();
+        assert_eq!(result.hex, "330267237da5535f");
+
+        let result = fingerprint("SELECT y, x FROM z").unwrap();
+        assert_eq!(result.hex, "330267237da5535f");
+
+        let result = fingerprint("INSERT INTO films (code, title, did) VALUES ('UA502', 'Bananas', 105), ('T_601', 'Yojimbo', DEFAULT)").unwrap();
+        assert_eq!(result.hex, "459fdc70778b841e");
+
+        let result =
+            fingerprint("INSERT INTO films (code, title, did) VALUES ($1, $2, $3)").unwrap();
+        assert_eq!(result.hex, "459fdc70778b841e");
+
+        let result = fingerprint("SELECT * FROM a").unwrap();
+        assert_eq!(result.hex, "fcf44da7b597ef43");
+
+        let result = fingerprint("SELECT * FROM a AS b").unwrap();
+        assert_eq!(result.hex, "fcf44da7b597ef43");
+
+        let result =
+            fingerprint("UPDATE users SET one_thing = $1, second_thing = $2 WHERE users.id = $1")
+                .unwrap();
+        assert_eq!(result.hex, "a0ea386c1cfd1e69");
+
+        let result =
+            fingerprint("UPDATE users SET something_else = $1 WHERE users.id = $1").unwrap();
+        assert_eq!(result.hex, "3172bc3e0d631d55");
+
+        let result = fingerprint("UPDATE users SET something_else = (SELECT a FROM x WHERE uid = users.id LIMIT 1) WHERE users.id = $1").unwrap();
+        assert_eq!(result.hex, "f1127a8b91fbecbf");
+
+        let result = fingerprint("SAVEPOINT some_id").unwrap();
+        assert_eq!(result.hex, "8ebd566ea1bf947b");
+
+        let result = fingerprint("RELEASE some_id").unwrap();
+        assert_eq!(result.hex, "60d618658252d2af");
+
+        let result = fingerprint("PREPARE TRANSACTION 'some_id'").unwrap();
+        assert_eq!(result.hex, "d993959a33d627d4");
+
+        let result = fingerprint("START TRANSACTION READ WRITE").unwrap();
+        assert_eq!(result.hex, "4ca25828c835d55a");
+
+        let result =
+            fingerprint("DECLARE cursor_123 CURSOR FOR SELECT * FROM test WHERE id = 123").unwrap();
+        assert_eq!(result.hex, "d2bec62d2a7ec7cb");
+
+        let result = fingerprint("FETCH 1000 FROM cursor_123").unwrap();
+        assert_eq!(result.hex, "37f4d2f6a957ae48");
+
+        let result = fingerprint("CLOSE cursor_123").unwrap();
+        assert_eq!(result.hex, "2c7963684fc2bad9");
+
+        let result = fingerprint("-- nothing").unwrap();
+        assert_eq!(result.hex, "d8d13f8b2da6c9ad");
+
+        let result = fingerprint("CREATE FOREIGN TABLE ft1 () SERVER no_server").unwrap();
+        assert_eq!(result.hex, "74481c4af7c76be1");
+
+        let result = fingerprint("UPDATE x SET a = 1, b = 2, c = 3").unwrap();
+        assert_eq!(result.hex, "fd5c248c0e642ce4");
+
+        let result = fingerprint("UPDATE x SET z = now()").unwrap();
+        assert_eq!(result.hex, "a222eaabaa1e7cb1");
+
+        let result = fingerprint(
+            "CREATE TEMPORARY TABLE my_temp_table (test_id integer NOT NULL) ON COMMIT DROP",
+        )
+        .unwrap();
+        assert_eq!(result.hex, "1407ed5c5bb00967");
+
+        let result = fingerprint("CREATE TEMPORARY TABLE my_temp_table AS SELECT 1").unwrap();
+        assert_eq!(result.hex, "695ebe73a3abc45c");
+
+        let result = fingerprint("SELECT INTERVAL (0) $2").unwrap();
+        assert_eq!(result.hex, "50fde20626009aba");
+
+        let result = fingerprint("SELECT INTERVAL (2) $2").unwrap();
+        assert_eq!(result.hex, "50fde20626009aba");
+
+        let result = fingerprint("SELECT * FROM t WHERE t.a IN (1, 2) AND t.b = 3").unwrap();
+        assert_eq!(result.hex, "346aea01be9173b6");
+
+        let result = fingerprint("SELECT * FROM t WHERE t.b = 3 AND t.a IN (1, 2)").unwrap();
+        assert_eq!(result.hex, "346aea01be9173b6");
+
+        let result = fingerprint("SELECT * FROM t WHERE a && '[1,2]'").unwrap();
+        assert_eq!(result.hex, "673f199f13dfe665");
+
+        let result = fingerprint("SELECT * FROM t WHERE a && '[1,2]'::int4range").unwrap();
+        assert_eq!(result.hex, "673f199f13dfe665");
+
+        let result = fingerprint("SELECT * FROM t_20210301_x").unwrap();
+        assert_eq!(result.hex, "6f8169980cd70a25");
+
+        let result = fingerprint("SELECT * FROM t_20210302_x").unwrap();
+        assert_eq!(result.hex, "6f8169980cd70a25");
+
+        let result = fingerprint("SELECT * FROM t_20210302_y").unwrap();
+        assert_eq!(result.hex, "d357dac4a24fcf1b");
+
+        let result = fingerprint("SELECT * FROM t_1").unwrap();
+        assert_eq!(result.hex, "018bd9230646143e");
+
+        let result = fingerprint("SELECT * FROM t_2").unwrap();
+        assert_eq!(result.hex, "3f1444da570c1a66");
+    }
+}
diff --git a/crates/pgt_query/src/iter_mut.rs b/crates/pgt_query/src/iter_mut.rs
new file mode 100644
index 000000000..fe5e88068
--- /dev/null
+++ b/crates/pgt_query/src/iter_mut.rs
@@ -0,0 +1 @@
+pgt_query_macros::iter_mut_codegen!();
diff --git a/crates/pgt_query/src/iter_ref.rs b/crates/pgt_query/src/iter_ref.rs
new file mode 100644
index 000000000..6ac4f220a
--- /dev/null
+++ b/crates/pgt_query/src/iter_ref.rs
@@ -0,0 +1 @@
+pgt_query_macros::iter_ref_codegen!();
diff --git a/crates/pgt_query/src/lib.rs b/crates/pgt_query/src/lib.rs
new file mode 100644
index 000000000..e89817196
--- /dev/null
+++ b/crates/pgt_query/src/lib.rs
@@ -0,0 +1,91 @@
+mod deparse;
+mod error;
+mod fingerprint;
+mod iter_mut;
+mod iter_ref;
+mod node_enum;
+mod node_mut;
+mod node_ref;
+mod node_structs;
+mod normalize;
+mod parse;
+mod plpgsql;
+mod scan;
+mod split;
+
+pub use deparse::*;
+pub use error::*;
+pub use fingerprint::*;
+pub use iter_mut::*;
+pub use iter_ref::*;
+pub use node_enum::*;
+pub use node_mut::*;
+pub use node_ref::*;
+pub use normalize::*;
+pub use parse::*;
+pub use plpgsql::*;
+pub use scan::*;
+pub use split::*;
+
+pub use protobuf::Node;
+
+// Include the generated bindings with 2024 edition compatibility
+#[allow(non_upper_case_globals)]
+#[allow(non_camel_case_types)]
+#[allow(non_snake_case)]
+#[allow(dead_code)]
+#[allow(improper_ctypes)]
+#[allow(unsafe_op_in_unsafe_fn)]
+mod bindings {
+    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+}
+
+// Include the generated protobuf code
+#[allow(clippy::all)]
+pub mod protobuf {
+    include!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/protobuf.rs"));
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn it_does_not_error_when_run_in_parallel() {
+        use easy_parallel::Parallel;
+
+        let mut queries = vec![];
+        for _ in 0..100 {
+            queries.push(
+            r#"
+            SELECT * FROM "t0"
+            JOIN "t1" ON (1) JOIN "t2" ON (1) JOIN "t3" ON (1) JOIN "t4" ON (1) JOIN "t5" ON (1)
+            JOIN "t6" ON (1) JOIN "t7" ON (1) JOIN "t8" ON (1) JOIN "t9" ON (1) JOIN "t10" ON (1)
+            JOIN "t11" ON (1) JOIN "t12" ON (1) JOIN "t13" ON (1) JOIN "t14" ON (1) JOIN "t15" ON (1)
+            JOIN "t16" ON (1) JOIN "t17" ON (1) JOIN "t18" ON (1) JOIN "t19" ON (1) JOIN "t20" ON (1)
+            JOIN "t21" ON (1) JOIN "t22" ON (1) JOIN "t23" ON (1) JOIN "t24" ON (1) JOIN "t25" ON (1)
+            JOIN "t26" ON (1) JOIN "t27" ON (1) JOIN "t28" ON (1) JOIN "t29" ON (1)
+        "#,
+        );
+            queries.push(
+            "
+            SELECT memory_total_bytes, memory_free_bytes, memory_pagecache_bytes, memory_buffers_bytes, memory_applications_bytes,
+                (memory_swap_total_bytes - memory_swap_free_bytes) AS swap, date_part($0, s.collected_at) AS collected_at
+            FROM snapshots s JOIN system_snapshots ON (snapshot_id = s.id)
+            WHERE s.database_id = $0 AND s.collected_at BETWEEN $0 AND $0
+            ORDER BY collected_at
+        ",
+        );
+        }
+
+        Parallel::new()
+            .each(queries, |query| {
+                for _ in 0..100 {
+                    let _result = parse(query).unwrap();
+                    fingerprint(query).unwrap();
+                    normalize(query).unwrap();
+                }
+            })
+            .run();
+    }
+}
diff --git a/crates/pgt_query/src/node_enum.rs b/crates/pgt_query/src/node_enum.rs
new file mode 100644
index 000000000..5d5b6bf71
--- /dev/null
+++ b/crates/pgt_query/src/node_enum.rs
@@ -0,0 +1,33 @@
+use crate::*;
+
+use protobuf::Node;
+pub use protobuf::node::Node as NodeEnum;
+
+pgt_query_macros::node_enum_codegen!();
+
+impl NodeEnum {
+    pub fn deparse(&self) -> Result<std::string::String> {
+        crate::deparse(&protobuf::ParseResult {
+            version: crate::bindings::PG_VERSION_NUM as i32,
+            stmts: vec![protobuf::RawStmt {
+                stmt: Some(Box::new(Node {
+                    node: Some(self.clone()),
+                })),
+                stmt_location: 0,
+                stmt_len: 0,
+            }],
+        })
+    }
+
+    pub fn nodes(&self) -> Vec<NodeRef<'_>> {
+        self.iter().collect()
+    }
+
+    pub fn iter(&self) -> NodeRefIterator<'_> {
+        NodeRefIterator::new(self.to_ref())
+    }
+
+    pub fn iter_mut(&mut self) -> NodeMutIterator {
+        NodeMutIterator::new(self.to_mut())
+    }
+}
diff --git a/crates/pgt_query/src/node_mut.rs b/crates/pgt_query/src/node_mut.rs
new file mode 100644
index 000000000..f2da254b2
--- /dev/null
+++ b/crates/pgt_query/src/node_mut.rs
@@ -0,0 +1,26 @@
+use protobuf::Node;
+
+pgt_query_macros::node_mut_codegen!();
+
+impl NodeMut {
+    pub fn deparse(&self) -> Result<std::string::String> {
+        crate::deparse(&protobuf::ParseResult {
+            version: crate::bindings::PG_VERSION_NUM as i32,
+            stmts: vec![protobuf::RawStmt {
+                stmt: Some(Box::new(Node {
+                    node: Some(self.to_enum()?),
+                })),
+                stmt_location: 0,
+                stmt_len: 0,
+            }],
+        })
+    }
+
+    pub fn nodes_mut(&self) -> Vec<NodeMut> {
+        self.iter_mut().collect()
+    }
+
+    pub fn iter_mut(&self) -> NodeMutIterator {
+        NodeMutIterator::new(*self)
+    }
+}
diff --git a/crates/pgt_query/src/node_ref.rs b/crates/pgt_query/src/node_ref.rs
new file mode 100644
index 000000000..603913cb7
--- /dev/null
+++ b/crates/pgt_query/src/node_ref.rs
@@ -0,0 +1,26 @@
+use protobuf::Node;
+
+pgt_query_macros::node_ref_codegen!();
+
+impl<'a> NodeRef<'a> {
+    pub fn deparse(&self) -> Result<std::string::String> {
+        crate::deparse(&protobuf::ParseResult {
+            version: crate::bindings::PG_VERSION_NUM as i32,
+            stmts: vec![protobuf::RawStmt {
+                stmt: Some(Box::new(Node {
+                    node: Some(self.to_enum()),
+                })),
+                stmt_location: 0,
+                stmt_len: 0,
+            }],
+        })
+    }
+
+    pub fn nodes(&self) -> Vec<NodeRef<'a>> {
+        self.iter().collect()
+    }
+
+    pub fn iter(&self) -> NodeRefIterator<'a> {
+        NodeRefIterator::new(*self)
+    }
+}
diff --git a/crates/pgt_query/src/node_structs.rs b/crates/pgt_query/src/node_structs.rs
new file mode 100644
index 000000000..8b81c98e5
--- /dev/null
+++ b/crates/pgt_query/src/node_structs.rs
@@ -0,0 +1,16 @@
+use protobuf::Node;
+
+pgt_query_macros::node_structs_codegen!();
+
+impl Node {
+    pub fn deparse(&self) -> Result<std::string::String> {
+        crate::deparse(&protobuf::ParseResult {
+            version: crate::bindings::PG_VERSION_NUM as i32,
+            stmts: vec![protobuf::RawStmt {
+                stmt: Some(Box::new(self.clone())),
+                stmt_location: 0,
+                stmt_len: 0,
+            }],
+        })
+    }
+}
diff --git a/crates/pgt_query/src/normalize.rs b/crates/pgt_query/src/normalize.rs
new file mode 100644
index 000000000..71ff683c7
--- /dev/null
+++ b/crates/pgt_query/src/normalize.rs
@@ -0,0 +1,136 @@
+use std::ffi::{CStr, CString};
+
+use crate::bindings::*;
+use crate::error::*;
+
+/// Normalizes the given SQL statement, returning a parametized version.
+///
+/// # Example
+///
+/// ```rust
+/// let result = pgt_query::normalize("SELECT * FROM contacts WHERE name='Paul'");
+/// assert!(result.is_ok());
+/// let result = result.unwrap();
+/// assert_eq!(result, "SELECT * FROM contacts WHERE name=$1");
+/// ```
+pub fn normalize(statement: &str) -> Result<std::string::String> {
+    let input = CString::new(statement).unwrap();
+    let result = unsafe { pg_query_normalize(input.as_ptr()) };
+    let normalized_query = if !result.error.is_null() {
+        let message = unsafe { CStr::from_ptr((*result.error).message) }
+            .to_string_lossy()
+            .to_string();
+        Err(Error::Parse(message))
+    } else {
+        let n = unsafe { CStr::from_ptr(result.normalized_query) };
+        Ok(n.to_string_lossy().to_string())
+    };
+    unsafe { pg_query_free_normalize_result(result) };
+    normalized_query
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::{Error, normalize};
+
+    #[test]
+    fn it_normalizes_simple_query() {
+        let result = normalize("SELECT 1").unwrap();
+        assert_eq!(result, "SELECT $1");
+    }
+
+    #[test]
+    fn it_normalizes_in() {
+        let result =
+            normalize("SELECT 1 FROM x WHERE y = 12561 AND z = '124' AND b IN (1, 2, 3)").unwrap();
+        assert_eq!(
+            result,
+            "SELECT $1 FROM x WHERE y = $2 AND z = $3 AND b IN ($4, $5, $6)"
+        );
+    }
+
+    #[test]
+    fn it_errors_on_invalid_input() {
+        let error = normalize("CREATE RANDOM ix_test ON contacts.person;")
+            .err()
+            .unwrap();
+        assert_eq!(
+            error,
+            Error::Parse("syntax error at or near \"RANDOM\"".into())
+        );
+    }
+
+    #[test]
+    fn it_normalizes_subselects() {
+        let result =
+            normalize("SELECT 1 FROM x WHERE y = (SELECT 123 FROM a WHERE z = 'bla')").unwrap();
+        assert_eq!(
+            result,
+            "SELECT $1 FROM x WHERE y = (SELECT $2 FROM a WHERE z = $3)"
+        );
+    }
+
+    #[test]
+    fn it_normalizes_any() {
+        let result = normalize("SELECT * FROM x WHERE y = ANY(array[1, 2])").unwrap();
+        assert_eq!(result, "SELECT * FROM x WHERE y = ANY(array[$1, $2])");
+
+        let result = normalize("SELECT * FROM x WHERE y = ANY(SELECT 1)").unwrap();
+        assert_eq!(result, "SELECT * FROM x WHERE y = ANY(SELECT $1)");
+    }
+
+    #[test]
+    fn it_normalizes_complicated_strings() {
+        let result = normalize("SELECT U&'d\\0061t\\+000061' FROM x").unwrap();
+        assert_eq!(result, "SELECT $1 FROM x");
+
+        let result = normalize("SELECT u&'d\\0061t\\+000061'    FROM x").unwrap();
+        assert_eq!(result, "SELECT $1    FROM x");
+
+        let result = normalize("SELECT * FROM x WHERE z NOT LIKE E'abc'AND TRUE").unwrap();
+        assert_eq!(result, "SELECT * FROM x WHERE z NOT LIKE $1AND $2");
+
+        let result = normalize("SELECT U&'d\\0061t\\+000061'-- comment\nFROM x").unwrap();
+        assert_eq!(result, "SELECT $1-- comment\nFROM x");
+    }
+
+    #[test]
+    fn it_normalizes_copy() {
+        let result = normalize("COPY (SELECT * FROM t WHERE id IN ('1', '2')) TO STDOUT").unwrap();
+        assert_eq!(
+            result,
+            "COPY (SELECT * FROM t WHERE id IN ($1, $2)) TO STDOUT"
+        );
+    }
+
+    #[test]
+    fn it_normalizes_set() {
+        let result = normalize("SET test=123").unwrap();
+        assert_eq!(result, "SET test=$1");
+
+        let result = normalize("SET CLIENT_ENCODING = UTF8").unwrap();
+        assert_eq!(result, "SET CLIENT_ENCODING = $1");
+    }
+
+    #[test]
+    fn it_does_not_error_on_deallocate() {
+        let result = normalize("DEALLOCATE bla; SELECT 1").unwrap();
+        assert_eq!(result, "DEALLOCATE bla; SELECT $1");
+    }
+
+    #[test]
+    fn it_normalizes_explain() {
+        let result = normalize("EXPLAIN SELECT x FROM y WHERE z = 1").unwrap();
+        assert_eq!(result, "EXPLAIN SELECT x FROM y WHERE z = $1");
+    }
+
+    #[test]
+    fn it_normalizes_declare_curson() {
+        let result =
+            normalize("DECLARE cursor_b CURSOR FOR SELECT * FROM databases WHERE id = 23").unwrap();
+        assert_eq!(
+            result,
+            "DECLARE cursor_b CURSOR FOR SELECT * FROM databases WHERE id = $1"
+        );
+    }
+}
diff --git a/crates/pgt_query/src/parse.rs b/crates/pgt_query/src/parse.rs
new file mode 100644
index 000000000..5853dfbc2
--- /dev/null
+++ b/crates/pgt_query/src/parse.rs
@@ -0,0 +1,149 @@
+use std::ffi::{CStr, CString};
+
+use crate::NodeEnum;
+use crate::bindings::*;
+use crate::error::*;
+use crate::protobuf;
+
+use prost::Message;
+
+/// Parses the given SQL statement into the given abstract syntax tree.
+///
+/// # Example
+///
+/// ```rust
+/// use pgt_query::parse;
+///
+/// let result = parse("SELECT * FROM contacts");
+/// assert!(result.is_ok());
+/// let result = result.unwrap();
+/// assert_eq!(result.protobuf.stmts.len(), 1);
+/// ```
+pub fn parse(statement: &str) -> Result<ParseResult> {
+    let input = CString::new(statement)?;
+    let result = unsafe { pg_query_parse_protobuf(input.as_ptr()) };
+    let parse_result = if !result.error.is_null() {
+        let message = unsafe { CStr::from_ptr((*result.error).message) }
+            .to_string_lossy()
+            .to_string();
+        Err(Error::Parse(message))
+    } else {
+        let data = unsafe {
+            std::slice::from_raw_parts(
+                result.parse_tree.data as *const u8,
+                result.parse_tree.len as usize,
+            )
+        };
+        let stderr = unsafe { CStr::from_ptr(result.stderr_buffer) }
+            .to_string_lossy()
+            .to_string();
+        protobuf::ParseResult::decode(data)
+            .map_err(Error::Decode)
+            .map(|result| ParseResult::new(result, stderr))
+    };
+    unsafe { pg_query_free_protobuf_parse_result(result) };
+    parse_result
+}
+
+/// The result of parsing a SQL query
+#[derive(Debug)]
+pub struct ParseResult {
+    /// The parsed protobuf result
+    pub protobuf: protobuf::ParseResult,
+    /// Warnings captured during parsing
+    pub warnings: Vec<String>,
+}
+
+impl ParseResult {
+    /// Create a new ParseResult
+    pub fn new(protobuf: protobuf::ParseResult, stderr: String) -> Self {
+        let warnings = stderr
+            .lines()
+            .filter_map(|l| {
+                if l.starts_with("WARNING") {
+                    Some(l.trim().into())
+                } else {
+                    None
+                }
+            })
+            .collect();
+
+        Self { protobuf, warnings }
+    }
+
+    pub fn deparse(&self) -> Result<String> {
+        crate::deparse(&self.protobuf)
+    }
+
+    pub fn stmts(&self) -> Vec<&NodeEnum> {
+        self.protobuf
+            .stmts
+            .iter()
+            .filter_map(|s| s.stmt.as_ref().and_then(|s| s.node.as_ref()))
+            .collect()
+    }
+
+    pub fn stmts_mut(&mut self) -> Vec<&mut NodeEnum> {
+        self.protobuf
+            .stmts
+            .iter_mut()
+            .filter_map(|s| s.stmt.as_mut().and_then(|s| s.node.as_mut()))
+            .collect()
+    }
+
+    /// Returns a reference to the root node of the parse tree.
+    ///
+    /// Returns None if there is not exactly one statement in the parse result.
+    pub fn root(&self) -> Option<&NodeEnum> {
+        if self.protobuf.stmts.len() != 1 {
+            return None;
+        }
+
+        // Get the first (and only) statement
+        let raw_stmt = &self.protobuf.stmts[0];
+
+        // Navigate: RawStmt -> Node -> NodeEnum
+        raw_stmt.stmt.as_ref().and_then(|stmt| stmt.node.as_ref())
+    }
+
+    /// Consumes the ParseResult and returns the root node of the parse tree.
+    ///
+    /// Returns None if there is not exactly one statement in the parse result.
+    /// This method avoids cloning by taking ownership of the ParseResult.
+    pub fn into_root(self) -> Option<NodeEnum> {
+        if self.protobuf.stmts.len() != 1 {
+            return None;
+        }
+
+        // Extract the first (and only) statement by taking ownership
+        let raw_stmt = self.protobuf.stmts.into_iter().next()?;
+
+        // Navigate: RawStmt -> Node -> NodeEnum
+        raw_stmt.stmt.and_then(|stmt| stmt.node)
+    }
+
+    /// Returns a mutable reference to the root node of the parse tree.
+    ///
+    /// Returns None if there is not exactly one statement in the parse result.
+    pub fn root_mut(&mut self) -> Option<&mut NodeEnum> {
+        if self.protobuf.stmts.len() != 1 {
+            return None;
+        }
+
+        // Get the first (and only) statement
+        let raw_stmt = &mut self.protobuf.stmts[0];
+
+        // Navigate: RawStmt -> Node -> NodeEnum
+        raw_stmt.stmt.as_mut().and_then(|stmt| stmt.node.as_mut())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::parse;
+
+    #[test]
+    fn it_parses_parameter_queries() {
+        assert!(parse("select $0 + $1 + $2 + $3 + $4 + $5").is_ok());
+    }
+}
diff --git a/crates/pgt_query/src/plpgsql.rs b/crates/pgt_query/src/plpgsql.rs
new file mode 100644
index 000000000..fbaa9694b
--- /dev/null
+++ b/crates/pgt_query/src/plpgsql.rs
@@ -0,0 +1,38 @@
+use std::ffi::{CStr, CString};
+
+use crate::bindings::*;
+use crate::error::*;
+
+/// An experimental API which parses a PLPGSQL function. This currently drops the returned
+/// structure and returns only a Result<()>.
+///
+/// # Example
+///
+/// ```rust
+/// let result = pgt_query::parse_plpgsql("
+///     CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar, v_version varchar)
+///     RETURNS varchar AS $$
+///     BEGIN
+///         IF v_version IS NULL THEN
+///             RETURN v_name;
+///         END IF;
+///         RETURN v_name || '/' || v_version;
+///     END;
+///     $$ LANGUAGE plpgsql;
+/// ");
+/// assert!(result.is_ok());
+/// ```
+pub fn parse_plpgsql(stmt: &str) -> Result<()> {
+    let input = CString::new(stmt)?;
+    let result = unsafe { pg_query_parse_plpgsql(input.as_ptr()) };
+    let structure = if !result.error.is_null() {
+        let message = unsafe { CStr::from_ptr((*result.error).message) }
+            .to_string_lossy()
+            .to_string();
+        Err(Error::Parse(message))
+    } else {
+        Ok(())
+    };
+    unsafe { pg_query_free_plpgsql_parse_result(result) };
+    structure
+}
diff --git a/crates/pgt_query/src/protobuf.rs b/crates/pgt_query/src/protobuf.rs
new file mode 100644
index 000000000..c47bfe52b
--- /dev/null
+++ b/crates/pgt_query/src/protobuf.rs
@@ -0,0 +1,8846 @@
+// This file is @generated by prost-build.
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ParseResult {
+    #[prost(int32, tag = "1")]
+    pub version: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub stmts: ::prost::alloc::vec::Vec<RawStmt>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ScanResult {
+    #[prost(int32, tag = "1")]
+    pub version: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub tokens: ::prost::alloc::vec::Vec<ScanToken>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct Node {
+    #[prost(
+        oneof = "node::Node",
+        tags = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268"
+    )]
+    pub node: ::core::option::Option<node::Node>,
+}
+/// Nested message and enum types in `Node`.
+pub mod node {
+    #[derive(Clone, PartialEq, ::prost::Oneof)]
+    pub enum Node {
+        #[prost(message, tag = "1")]
+        Alias(super::Alias),
+        #[prost(message, tag = "2")]
+        RangeVar(super::RangeVar),
+        #[prost(message, tag = "3")]
+        TableFunc(::prost::alloc::boxed::Box<super::TableFunc>),
+        #[prost(message, tag = "4")]
+        IntoClause(::prost::alloc::boxed::Box<super::IntoClause>),
+        #[prost(message, tag = "5")]
+        Var(::prost::alloc::boxed::Box<super::Var>),
+        #[prost(message, tag = "6")]
+        Param(::prost::alloc::boxed::Box<super::Param>),
+        #[prost(message, tag = "7")]
+        Aggref(::prost::alloc::boxed::Box<super::Aggref>),
+        #[prost(message, tag = "8")]
+        GroupingFunc(::prost::alloc::boxed::Box<super::GroupingFunc>),
+        #[prost(message, tag = "9")]
+        WindowFunc(::prost::alloc::boxed::Box<super::WindowFunc>),
+        #[prost(message, tag = "10")]
+        WindowFuncRunCondition(
+            ::prost::alloc::boxed::Box<super::WindowFuncRunCondition>,
+        ),
+        #[prost(message, tag = "11")]
+        MergeSupportFunc(::prost::alloc::boxed::Box<super::MergeSupportFunc>),
+        #[prost(message, tag = "12")]
+        SubscriptingRef(::prost::alloc::boxed::Box<super::SubscriptingRef>),
+        #[prost(message, tag = "13")]
+        FuncExpr(::prost::alloc::boxed::Box<super::FuncExpr>),
+        #[prost(message, tag = "14")]
+        NamedArgExpr(::prost::alloc::boxed::Box<super::NamedArgExpr>),
+        #[prost(message, tag = "15")]
+        OpExpr(::prost::alloc::boxed::Box<super::OpExpr>),
+        #[prost(message, tag = "16")]
+        DistinctExpr(::prost::alloc::boxed::Box<super::DistinctExpr>),
+        #[prost(message, tag = "17")]
+        NullIfExpr(::prost::alloc::boxed::Box<super::NullIfExpr>),
+        #[prost(message, tag = "18")]
+        ScalarArrayOpExpr(::prost::alloc::boxed::Box<super::ScalarArrayOpExpr>),
+        #[prost(message, tag = "19")]
+        BoolExpr(::prost::alloc::boxed::Box<super::BoolExpr>),
+        #[prost(message, tag = "20")]
+        SubLink(::prost::alloc::boxed::Box<super::SubLink>),
+        #[prost(message, tag = "21")]
+        SubPlan(::prost::alloc::boxed::Box<super::SubPlan>),
+        #[prost(message, tag = "22")]
+        AlternativeSubPlan(::prost::alloc::boxed::Box<super::AlternativeSubPlan>),
+        #[prost(message, tag = "23")]
+        FieldSelect(::prost::alloc::boxed::Box<super::FieldSelect>),
+        #[prost(message, tag = "24")]
+        FieldStore(::prost::alloc::boxed::Box<super::FieldStore>),
+        #[prost(message, tag = "25")]
+        RelabelType(::prost::alloc::boxed::Box<super::RelabelType>),
+        #[prost(message, tag = "26")]
+        CoerceViaIo(::prost::alloc::boxed::Box<super::CoerceViaIo>),
+        #[prost(message, tag = "27")]
+        ArrayCoerceExpr(::prost::alloc::boxed::Box<super::ArrayCoerceExpr>),
+        #[prost(message, tag = "28")]
+        ConvertRowtypeExpr(::prost::alloc::boxed::Box<super::ConvertRowtypeExpr>),
+        #[prost(message, tag = "29")]
+        CollateExpr(::prost::alloc::boxed::Box<super::CollateExpr>),
+        #[prost(message, tag = "30")]
+        CaseExpr(::prost::alloc::boxed::Box<super::CaseExpr>),
+        #[prost(message, tag = "31")]
+        CaseWhen(::prost::alloc::boxed::Box<super::CaseWhen>),
+        #[prost(message, tag = "32")]
+        CaseTestExpr(::prost::alloc::boxed::Box<super::CaseTestExpr>),
+        #[prost(message, tag = "33")]
+        ArrayExpr(::prost::alloc::boxed::Box<super::ArrayExpr>),
+        #[prost(message, tag = "34")]
+        RowExpr(::prost::alloc::boxed::Box<super::RowExpr>),
+        #[prost(message, tag = "35")]
+        RowCompareExpr(::prost::alloc::boxed::Box<super::RowCompareExpr>),
+        #[prost(message, tag = "36")]
+        CoalesceExpr(::prost::alloc::boxed::Box<super::CoalesceExpr>),
+        #[prost(message, tag = "37")]
+        MinMaxExpr(::prost::alloc::boxed::Box<super::MinMaxExpr>),
+        #[prost(message, tag = "38")]
+        SqlvalueFunction(::prost::alloc::boxed::Box<super::SqlValueFunction>),
+        #[prost(message, tag = "39")]
+        XmlExpr(::prost::alloc::boxed::Box<super::XmlExpr>),
+        #[prost(message, tag = "40")]
+        JsonFormat(super::JsonFormat),
+        #[prost(message, tag = "41")]
+        JsonReturning(super::JsonReturning),
+        #[prost(message, tag = "42")]
+        JsonValueExpr(::prost::alloc::boxed::Box<super::JsonValueExpr>),
+        #[prost(message, tag = "43")]
+        JsonConstructorExpr(::prost::alloc::boxed::Box<super::JsonConstructorExpr>),
+        #[prost(message, tag = "44")]
+        JsonIsPredicate(::prost::alloc::boxed::Box<super::JsonIsPredicate>),
+        #[prost(message, tag = "45")]
+        JsonBehavior(::prost::alloc::boxed::Box<super::JsonBehavior>),
+        #[prost(message, tag = "46")]
+        JsonExpr(::prost::alloc::boxed::Box<super::JsonExpr>),
+        #[prost(message, tag = "47")]
+        JsonTablePath(super::JsonTablePath),
+        #[prost(message, tag = "48")]
+        JsonTablePathScan(::prost::alloc::boxed::Box<super::JsonTablePathScan>),
+        #[prost(message, tag = "49")]
+        JsonTableSiblingJoin(::prost::alloc::boxed::Box<super::JsonTableSiblingJoin>),
+        #[prost(message, tag = "50")]
+        NullTest(::prost::alloc::boxed::Box<super::NullTest>),
+        #[prost(message, tag = "51")]
+        BooleanTest(::prost::alloc::boxed::Box<super::BooleanTest>),
+        #[prost(message, tag = "52")]
+        MergeAction(::prost::alloc::boxed::Box<super::MergeAction>),
+        #[prost(message, tag = "53")]
+        CoerceToDomain(::prost::alloc::boxed::Box<super::CoerceToDomain>),
+        #[prost(message, tag = "54")]
+        CoerceToDomainValue(::prost::alloc::boxed::Box<super::CoerceToDomainValue>),
+        #[prost(message, tag = "55")]
+        SetToDefault(::prost::alloc::boxed::Box<super::SetToDefault>),
+        #[prost(message, tag = "56")]
+        CurrentOfExpr(::prost::alloc::boxed::Box<super::CurrentOfExpr>),
+        #[prost(message, tag = "57")]
+        NextValueExpr(::prost::alloc::boxed::Box<super::NextValueExpr>),
+        #[prost(message, tag = "58")]
+        InferenceElem(::prost::alloc::boxed::Box<super::InferenceElem>),
+        #[prost(message, tag = "59")]
+        TargetEntry(::prost::alloc::boxed::Box<super::TargetEntry>),
+        #[prost(message, tag = "60")]
+        RangeTblRef(super::RangeTblRef),
+        #[prost(message, tag = "61")]
+        JoinExpr(::prost::alloc::boxed::Box<super::JoinExpr>),
+        #[prost(message, tag = "62")]
+        FromExpr(::prost::alloc::boxed::Box<super::FromExpr>),
+        #[prost(message, tag = "63")]
+        OnConflictExpr(::prost::alloc::boxed::Box<super::OnConflictExpr>),
+        #[prost(message, tag = "64")]
+        Query(::prost::alloc::boxed::Box<super::Query>),
+        #[prost(message, tag = "65")]
+        TypeName(super::TypeName),
+        #[prost(message, tag = "66")]
+        ColumnRef(super::ColumnRef),
+        #[prost(message, tag = "67")]
+        ParamRef(super::ParamRef),
+        #[prost(message, tag = "68")]
+        AExpr(::prost::alloc::boxed::Box<super::AExpr>),
+        #[prost(message, tag = "69")]
+        TypeCast(::prost::alloc::boxed::Box<super::TypeCast>),
+        #[prost(message, tag = "70")]
+        CollateClause(::prost::alloc::boxed::Box<super::CollateClause>),
+        #[prost(message, tag = "71")]
+        RoleSpec(super::RoleSpec),
+        #[prost(message, tag = "72")]
+        FuncCall(::prost::alloc::boxed::Box<super::FuncCall>),
+        #[prost(message, tag = "73")]
+        AStar(super::AStar),
+        #[prost(message, tag = "74")]
+        AIndices(::prost::alloc::boxed::Box<super::AIndices>),
+        #[prost(message, tag = "75")]
+        AIndirection(::prost::alloc::boxed::Box<super::AIndirection>),
+        #[prost(message, tag = "76")]
+        AArrayExpr(super::AArrayExpr),
+        #[prost(message, tag = "77")]
+        ResTarget(::prost::alloc::boxed::Box<super::ResTarget>),
+        #[prost(message, tag = "78")]
+        MultiAssignRef(::prost::alloc::boxed::Box<super::MultiAssignRef>),
+        #[prost(message, tag = "79")]
+        SortBy(::prost::alloc::boxed::Box<super::SortBy>),
+        #[prost(message, tag = "80")]
+        WindowDef(::prost::alloc::boxed::Box<super::WindowDef>),
+        #[prost(message, tag = "81")]
+        RangeSubselect(::prost::alloc::boxed::Box<super::RangeSubselect>),
+        #[prost(message, tag = "82")]
+        RangeFunction(super::RangeFunction),
+        #[prost(message, tag = "83")]
+        RangeTableFunc(::prost::alloc::boxed::Box<super::RangeTableFunc>),
+        #[prost(message, tag = "84")]
+        RangeTableFuncCol(::prost::alloc::boxed::Box<super::RangeTableFuncCol>),
+        #[prost(message, tag = "85")]
+        RangeTableSample(::prost::alloc::boxed::Box<super::RangeTableSample>),
+        #[prost(message, tag = "86")]
+        ColumnDef(::prost::alloc::boxed::Box<super::ColumnDef>),
+        #[prost(message, tag = "87")]
+        TableLikeClause(super::TableLikeClause),
+        #[prost(message, tag = "88")]
+        IndexElem(::prost::alloc::boxed::Box<super::IndexElem>),
+        #[prost(message, tag = "89")]
+        DefElem(::prost::alloc::boxed::Box<super::DefElem>),
+        #[prost(message, tag = "90")]
+        LockingClause(super::LockingClause),
+        #[prost(message, tag = "91")]
+        XmlSerialize(::prost::alloc::boxed::Box<super::XmlSerialize>),
+        #[prost(message, tag = "92")]
+        PartitionElem(::prost::alloc::boxed::Box<super::PartitionElem>),
+        #[prost(message, tag = "93")]
+        PartitionSpec(super::PartitionSpec),
+        #[prost(message, tag = "94")]
+        PartitionBoundSpec(super::PartitionBoundSpec),
+        #[prost(message, tag = "95")]
+        PartitionRangeDatum(::prost::alloc::boxed::Box<super::PartitionRangeDatum>),
+        #[prost(message, tag = "96")]
+        SinglePartitionSpec(super::SinglePartitionSpec),
+        #[prost(message, tag = "97")]
+        PartitionCmd(super::PartitionCmd),
+        #[prost(message, tag = "98")]
+        RangeTblEntry(::prost::alloc::boxed::Box<super::RangeTblEntry>),
+        #[prost(message, tag = "99")]
+        RtepermissionInfo(super::RtePermissionInfo),
+        #[prost(message, tag = "100")]
+        RangeTblFunction(::prost::alloc::boxed::Box<super::RangeTblFunction>),
+        #[prost(message, tag = "101")]
+        TableSampleClause(::prost::alloc::boxed::Box<super::TableSampleClause>),
+        #[prost(message, tag = "102")]
+        WithCheckOption(::prost::alloc::boxed::Box<super::WithCheckOption>),
+        #[prost(message, tag = "103")]
+        SortGroupClause(super::SortGroupClause),
+        #[prost(message, tag = "104")]
+        GroupingSet(super::GroupingSet),
+        #[prost(message, tag = "105")]
+        WindowClause(::prost::alloc::boxed::Box<super::WindowClause>),
+        #[prost(message, tag = "106")]
+        RowMarkClause(super::RowMarkClause),
+        #[prost(message, tag = "107")]
+        WithClause(super::WithClause),
+        #[prost(message, tag = "108")]
+        InferClause(::prost::alloc::boxed::Box<super::InferClause>),
+        #[prost(message, tag = "109")]
+        OnConflictClause(::prost::alloc::boxed::Box<super::OnConflictClause>),
+        #[prost(message, tag = "110")]
+        CtesearchClause(super::CteSearchClause),
+        #[prost(message, tag = "111")]
+        CtecycleClause(::prost::alloc::boxed::Box<super::CteCycleClause>),
+        #[prost(message, tag = "112")]
+        CommonTableExpr(::prost::alloc::boxed::Box<super::CommonTableExpr>),
+        #[prost(message, tag = "113")]
+        MergeWhenClause(::prost::alloc::boxed::Box<super::MergeWhenClause>),
+        #[prost(message, tag = "114")]
+        TriggerTransition(super::TriggerTransition),
+        #[prost(message, tag = "115")]
+        JsonOutput(super::JsonOutput),
+        #[prost(message, tag = "116")]
+        JsonArgument(::prost::alloc::boxed::Box<super::JsonArgument>),
+        #[prost(message, tag = "117")]
+        JsonFuncExpr(::prost::alloc::boxed::Box<super::JsonFuncExpr>),
+        #[prost(message, tag = "118")]
+        JsonTablePathSpec(::prost::alloc::boxed::Box<super::JsonTablePathSpec>),
+        #[prost(message, tag = "119")]
+        JsonTable(::prost::alloc::boxed::Box<super::JsonTable>),
+        #[prost(message, tag = "120")]
+        JsonTableColumn(::prost::alloc::boxed::Box<super::JsonTableColumn>),
+        #[prost(message, tag = "121")]
+        JsonKeyValue(::prost::alloc::boxed::Box<super::JsonKeyValue>),
+        #[prost(message, tag = "122")]
+        JsonParseExpr(::prost::alloc::boxed::Box<super::JsonParseExpr>),
+        #[prost(message, tag = "123")]
+        JsonScalarExpr(::prost::alloc::boxed::Box<super::JsonScalarExpr>),
+        #[prost(message, tag = "124")]
+        JsonSerializeExpr(::prost::alloc::boxed::Box<super::JsonSerializeExpr>),
+        #[prost(message, tag = "125")]
+        JsonObjectConstructor(super::JsonObjectConstructor),
+        #[prost(message, tag = "126")]
+        JsonArrayConstructor(super::JsonArrayConstructor),
+        #[prost(message, tag = "127")]
+        JsonArrayQueryConstructor(
+            ::prost::alloc::boxed::Box<super::JsonArrayQueryConstructor>,
+        ),
+        #[prost(message, tag = "128")]
+        JsonAggConstructor(::prost::alloc::boxed::Box<super::JsonAggConstructor>),
+        #[prost(message, tag = "129")]
+        JsonObjectAgg(::prost::alloc::boxed::Box<super::JsonObjectAgg>),
+        #[prost(message, tag = "130")]
+        JsonArrayAgg(::prost::alloc::boxed::Box<super::JsonArrayAgg>),
+        #[prost(message, tag = "131")]
+        RawStmt(::prost::alloc::boxed::Box<super::RawStmt>),
+        #[prost(message, tag = "132")]
+        InsertStmt(::prost::alloc::boxed::Box<super::InsertStmt>),
+        #[prost(message, tag = "133")]
+        DeleteStmt(::prost::alloc::boxed::Box<super::DeleteStmt>),
+        #[prost(message, tag = "134")]
+        UpdateStmt(::prost::alloc::boxed::Box<super::UpdateStmt>),
+        #[prost(message, tag = "135")]
+        MergeStmt(::prost::alloc::boxed::Box<super::MergeStmt>),
+        #[prost(message, tag = "136")]
+        SelectStmt(::prost::alloc::boxed::Box<super::SelectStmt>),
+        #[prost(message, tag = "137")]
+        SetOperationStmt(::prost::alloc::boxed::Box<super::SetOperationStmt>),
+        #[prost(message, tag = "138")]
+        ReturnStmt(::prost::alloc::boxed::Box<super::ReturnStmt>),
+        #[prost(message, tag = "139")]
+        PlassignStmt(::prost::alloc::boxed::Box<super::PlAssignStmt>),
+        #[prost(message, tag = "140")]
+        CreateSchemaStmt(super::CreateSchemaStmt),
+        #[prost(message, tag = "141")]
+        AlterTableStmt(super::AlterTableStmt),
+        #[prost(message, tag = "142")]
+        ReplicaIdentityStmt(super::ReplicaIdentityStmt),
+        #[prost(message, tag = "143")]
+        AlterTableCmd(::prost::alloc::boxed::Box<super::AlterTableCmd>),
+        #[prost(message, tag = "144")]
+        AlterCollationStmt(super::AlterCollationStmt),
+        #[prost(message, tag = "145")]
+        AlterDomainStmt(::prost::alloc::boxed::Box<super::AlterDomainStmt>),
+        #[prost(message, tag = "146")]
+        GrantStmt(super::GrantStmt),
+        #[prost(message, tag = "147")]
+        ObjectWithArgs(super::ObjectWithArgs),
+        #[prost(message, tag = "148")]
+        AccessPriv(super::AccessPriv),
+        #[prost(message, tag = "149")]
+        GrantRoleStmt(super::GrantRoleStmt),
+        #[prost(message, tag = "150")]
+        AlterDefaultPrivilegesStmt(super::AlterDefaultPrivilegesStmt),
+        #[prost(message, tag = "151")]
+        CopyStmt(::prost::alloc::boxed::Box<super::CopyStmt>),
+        #[prost(message, tag = "152")]
+        VariableSetStmt(super::VariableSetStmt),
+        #[prost(message, tag = "153")]
+        VariableShowStmt(super::VariableShowStmt),
+        #[prost(message, tag = "154")]
+        CreateStmt(super::CreateStmt),
+        #[prost(message, tag = "155")]
+        Constraint(::prost::alloc::boxed::Box<super::Constraint>),
+        #[prost(message, tag = "156")]
+        CreateTableSpaceStmt(super::CreateTableSpaceStmt),
+        #[prost(message, tag = "157")]
+        DropTableSpaceStmt(super::DropTableSpaceStmt),
+        #[prost(message, tag = "158")]
+        AlterTableSpaceOptionsStmt(super::AlterTableSpaceOptionsStmt),
+        #[prost(message, tag = "159")]
+        AlterTableMoveAllStmt(super::AlterTableMoveAllStmt),
+        #[prost(message, tag = "160")]
+        CreateExtensionStmt(super::CreateExtensionStmt),
+        #[prost(message, tag = "161")]
+        AlterExtensionStmt(super::AlterExtensionStmt),
+        #[prost(message, tag = "162")]
+        AlterExtensionContentsStmt(
+            ::prost::alloc::boxed::Box<super::AlterExtensionContentsStmt>,
+        ),
+        #[prost(message, tag = "163")]
+        CreateFdwStmt(super::CreateFdwStmt),
+        #[prost(message, tag = "164")]
+        AlterFdwStmt(super::AlterFdwStmt),
+        #[prost(message, tag = "165")]
+        CreateForeignServerStmt(super::CreateForeignServerStmt),
+        #[prost(message, tag = "166")]
+        AlterForeignServerStmt(super::AlterForeignServerStmt),
+        #[prost(message, tag = "167")]
+        CreateForeignTableStmt(super::CreateForeignTableStmt),
+        #[prost(message, tag = "168")]
+        CreateUserMappingStmt(super::CreateUserMappingStmt),
+        #[prost(message, tag = "169")]
+        AlterUserMappingStmt(super::AlterUserMappingStmt),
+        #[prost(message, tag = "170")]
+        DropUserMappingStmt(super::DropUserMappingStmt),
+        #[prost(message, tag = "171")]
+        ImportForeignSchemaStmt(super::ImportForeignSchemaStmt),
+        #[prost(message, tag = "172")]
+        CreatePolicyStmt(::prost::alloc::boxed::Box<super::CreatePolicyStmt>),
+        #[prost(message, tag = "173")]
+        AlterPolicyStmt(::prost::alloc::boxed::Box<super::AlterPolicyStmt>),
+        #[prost(message, tag = "174")]
+        CreateAmStmt(super::CreateAmStmt),
+        #[prost(message, tag = "175")]
+        CreateTrigStmt(::prost::alloc::boxed::Box<super::CreateTrigStmt>),
+        #[prost(message, tag = "176")]
+        CreateEventTrigStmt(super::CreateEventTrigStmt),
+        #[prost(message, tag = "177")]
+        AlterEventTrigStmt(super::AlterEventTrigStmt),
+        #[prost(message, tag = "178")]
+        CreatePlangStmt(super::CreatePLangStmt),
+        #[prost(message, tag = "179")]
+        CreateRoleStmt(super::CreateRoleStmt),
+        #[prost(message, tag = "180")]
+        AlterRoleStmt(super::AlterRoleStmt),
+        #[prost(message, tag = "181")]
+        AlterRoleSetStmt(super::AlterRoleSetStmt),
+        #[prost(message, tag = "182")]
+        DropRoleStmt(super::DropRoleStmt),
+        #[prost(message, tag = "183")]
+        CreateSeqStmt(super::CreateSeqStmt),
+        #[prost(message, tag = "184")]
+        AlterSeqStmt(super::AlterSeqStmt),
+        #[prost(message, tag = "185")]
+        DefineStmt(super::DefineStmt),
+        #[prost(message, tag = "186")]
+        CreateDomainStmt(::prost::alloc::boxed::Box<super::CreateDomainStmt>),
+        #[prost(message, tag = "187")]
+        CreateOpClassStmt(super::CreateOpClassStmt),
+        #[prost(message, tag = "188")]
+        CreateOpClassItem(super::CreateOpClassItem),
+        #[prost(message, tag = "189")]
+        CreateOpFamilyStmt(super::CreateOpFamilyStmt),
+        #[prost(message, tag = "190")]
+        AlterOpFamilyStmt(super::AlterOpFamilyStmt),
+        #[prost(message, tag = "191")]
+        DropStmt(super::DropStmt),
+        #[prost(message, tag = "192")]
+        TruncateStmt(super::TruncateStmt),
+        #[prost(message, tag = "193")]
+        CommentStmt(::prost::alloc::boxed::Box<super::CommentStmt>),
+        #[prost(message, tag = "194")]
+        SecLabelStmt(::prost::alloc::boxed::Box<super::SecLabelStmt>),
+        #[prost(message, tag = "195")]
+        DeclareCursorStmt(::prost::alloc::boxed::Box<super::DeclareCursorStmt>),
+        #[prost(message, tag = "196")]
+        ClosePortalStmt(super::ClosePortalStmt),
+        #[prost(message, tag = "197")]
+        FetchStmt(super::FetchStmt),
+        #[prost(message, tag = "198")]
+        IndexStmt(::prost::alloc::boxed::Box<super::IndexStmt>),
+        #[prost(message, tag = "199")]
+        CreateStatsStmt(super::CreateStatsStmt),
+        #[prost(message, tag = "200")]
+        StatsElem(::prost::alloc::boxed::Box<super::StatsElem>),
+        #[prost(message, tag = "201")]
+        AlterStatsStmt(::prost::alloc::boxed::Box<super::AlterStatsStmt>),
+        #[prost(message, tag = "202")]
+        CreateFunctionStmt(::prost::alloc::boxed::Box<super::CreateFunctionStmt>),
+        #[prost(message, tag = "203")]
+        FunctionParameter(::prost::alloc::boxed::Box<super::FunctionParameter>),
+        #[prost(message, tag = "204")]
+        AlterFunctionStmt(super::AlterFunctionStmt),
+        #[prost(message, tag = "205")]
+        DoStmt(super::DoStmt),
+        #[prost(message, tag = "206")]
+        InlineCodeBlock(super::InlineCodeBlock),
+        #[prost(message, tag = "207")]
+        CallStmt(::prost::alloc::boxed::Box<super::CallStmt>),
+        #[prost(message, tag = "208")]
+        CallContext(super::CallContext),
+        #[prost(message, tag = "209")]
+        RenameStmt(::prost::alloc::boxed::Box<super::RenameStmt>),
+        #[prost(message, tag = "210")]
+        AlterObjectDependsStmt(
+            ::prost::alloc::boxed::Box<super::AlterObjectDependsStmt>,
+        ),
+        #[prost(message, tag = "211")]
+        AlterObjectSchemaStmt(::prost::alloc::boxed::Box<super::AlterObjectSchemaStmt>),
+        #[prost(message, tag = "212")]
+        AlterOwnerStmt(::prost::alloc::boxed::Box<super::AlterOwnerStmt>),
+        #[prost(message, tag = "213")]
+        AlterOperatorStmt(super::AlterOperatorStmt),
+        #[prost(message, tag = "214")]
+        AlterTypeStmt(super::AlterTypeStmt),
+        #[prost(message, tag = "215")]
+        RuleStmt(::prost::alloc::boxed::Box<super::RuleStmt>),
+        #[prost(message, tag = "216")]
+        NotifyStmt(super::NotifyStmt),
+        #[prost(message, tag = "217")]
+        ListenStmt(super::ListenStmt),
+        #[prost(message, tag = "218")]
+        UnlistenStmt(super::UnlistenStmt),
+        #[prost(message, tag = "219")]
+        TransactionStmt(super::TransactionStmt),
+        #[prost(message, tag = "220")]
+        CompositeTypeStmt(super::CompositeTypeStmt),
+        #[prost(message, tag = "221")]
+        CreateEnumStmt(super::CreateEnumStmt),
+        #[prost(message, tag = "222")]
+        CreateRangeStmt(super::CreateRangeStmt),
+        #[prost(message, tag = "223")]
+        AlterEnumStmt(super::AlterEnumStmt),
+        #[prost(message, tag = "224")]
+        ViewStmt(::prost::alloc::boxed::Box<super::ViewStmt>),
+        #[prost(message, tag = "225")]
+        LoadStmt(super::LoadStmt),
+        #[prost(message, tag = "226")]
+        CreatedbStmt(super::CreatedbStmt),
+        #[prost(message, tag = "227")]
+        AlterDatabaseStmt(super::AlterDatabaseStmt),
+        #[prost(message, tag = "228")]
+        AlterDatabaseRefreshCollStmt(super::AlterDatabaseRefreshCollStmt),
+        #[prost(message, tag = "229")]
+        AlterDatabaseSetStmt(super::AlterDatabaseSetStmt),
+        #[prost(message, tag = "230")]
+        DropdbStmt(super::DropdbStmt),
+        #[prost(message, tag = "231")]
+        AlterSystemStmt(super::AlterSystemStmt),
+        #[prost(message, tag = "232")]
+        ClusterStmt(super::ClusterStmt),
+        #[prost(message, tag = "233")]
+        VacuumStmt(super::VacuumStmt),
+        #[prost(message, tag = "234")]
+        VacuumRelation(super::VacuumRelation),
+        #[prost(message, tag = "235")]
+        ExplainStmt(::prost::alloc::boxed::Box<super::ExplainStmt>),
+        #[prost(message, tag = "236")]
+        CreateTableAsStmt(::prost::alloc::boxed::Box<super::CreateTableAsStmt>),
+        #[prost(message, tag = "237")]
+        RefreshMatViewStmt(super::RefreshMatViewStmt),
+        #[prost(message, tag = "238")]
+        CheckPointStmt(super::CheckPointStmt),
+        #[prost(message, tag = "239")]
+        DiscardStmt(super::DiscardStmt),
+        #[prost(message, tag = "240")]
+        LockStmt(super::LockStmt),
+        #[prost(message, tag = "241")]
+        ConstraintsSetStmt(super::ConstraintsSetStmt),
+        #[prost(message, tag = "242")]
+        ReindexStmt(super::ReindexStmt),
+        #[prost(message, tag = "243")]
+        CreateConversionStmt(super::CreateConversionStmt),
+        #[prost(message, tag = "244")]
+        CreateCastStmt(super::CreateCastStmt),
+        #[prost(message, tag = "245")]
+        CreateTransformStmt(super::CreateTransformStmt),
+        #[prost(message, tag = "246")]
+        PrepareStmt(::prost::alloc::boxed::Box<super::PrepareStmt>),
+        #[prost(message, tag = "247")]
+        ExecuteStmt(super::ExecuteStmt),
+        #[prost(message, tag = "248")]
+        DeallocateStmt(super::DeallocateStmt),
+        #[prost(message, tag = "249")]
+        DropOwnedStmt(super::DropOwnedStmt),
+        #[prost(message, tag = "250")]
+        ReassignOwnedStmt(super::ReassignOwnedStmt),
+        #[prost(message, tag = "251")]
+        AlterTsdictionaryStmt(super::AlterTsDictionaryStmt),
+        #[prost(message, tag = "252")]
+        AlterTsconfigurationStmt(super::AlterTsConfigurationStmt),
+        #[prost(message, tag = "253")]
+        PublicationTable(::prost::alloc::boxed::Box<super::PublicationTable>),
+        #[prost(message, tag = "254")]
+        PublicationObjSpec(::prost::alloc::boxed::Box<super::PublicationObjSpec>),
+        #[prost(message, tag = "255")]
+        CreatePublicationStmt(super::CreatePublicationStmt),
+        #[prost(message, tag = "256")]
+        AlterPublicationStmt(super::AlterPublicationStmt),
+        #[prost(message, tag = "257")]
+        CreateSubscriptionStmt(super::CreateSubscriptionStmt),
+        #[prost(message, tag = "258")]
+        AlterSubscriptionStmt(super::AlterSubscriptionStmt),
+        #[prost(message, tag = "259")]
+        DropSubscriptionStmt(super::DropSubscriptionStmt),
+        #[prost(message, tag = "260")]
+        Integer(super::Integer),
+        #[prost(message, tag = "261")]
+        Float(super::Float),
+        #[prost(message, tag = "262")]
+        Boolean(super::Boolean),
+        #[prost(message, tag = "263")]
+        String(super::String),
+        #[prost(message, tag = "264")]
+        BitString(super::BitString),
+        #[prost(message, tag = "265")]
+        List(super::List),
+        #[prost(message, tag = "266")]
+        IntList(super::IntList),
+        #[prost(message, tag = "267")]
+        OidList(super::OidList),
+        #[prost(message, tag = "268")]
+        AConst(super::AConst),
+    }
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct Integer {
+    /// machine integer
+    #[prost(int32, tag = "1")]
+    pub ival: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct Float {
+    /// string
+    #[prost(string, tag = "1")]
+    pub fval: ::prost::alloc::string::String,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct Boolean {
+    #[prost(bool, tag = "1")]
+    pub boolval: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct String {
+    /// string
+    #[prost(string, tag = "1")]
+    pub sval: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct BitString {
+    /// string
+    #[prost(string, tag = "1")]
+    pub bsval: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct List {
+    #[prost(message, repeated, tag = "1")]
+    pub items: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct OidList {
+    #[prost(message, repeated, tag = "1")]
+    pub items: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct IntList {
+    #[prost(message, repeated, tag = "1")]
+    pub items: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AConst {
+    #[prost(bool, tag = "10")]
+    pub isnull: bool,
+    #[prost(int32, tag = "11")]
+    pub location: i32,
+    #[prost(oneof = "a_const::Val", tags = "1, 2, 3, 4, 5")]
+    pub val: ::core::option::Option<a_const::Val>,
+}
+/// Nested message and enum types in `A_Const`.
+pub mod a_const {
+    #[derive(Clone, PartialEq, ::prost::Oneof)]
+    pub enum Val {
+        #[prost(message, tag = "1")]
+        Ival(super::Integer),
+        #[prost(message, tag = "2")]
+        Fval(super::Float),
+        #[prost(message, tag = "3")]
+        Boolval(super::Boolean),
+        #[prost(message, tag = "4")]
+        Sval(super::String),
+        #[prost(message, tag = "5")]
+        Bsval(super::BitString),
+    }
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct Alias {
+    #[prost(string, tag = "1")]
+    pub aliasname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub colnames: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RangeVar {
+    #[prost(string, tag = "1")]
+    pub catalogname: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub schemaname: ::prost::alloc::string::String,
+    #[prost(string, tag = "3")]
+    pub relname: ::prost::alloc::string::String,
+    #[prost(bool, tag = "4")]
+    pub inh: bool,
+    #[prost(string, tag = "5")]
+    pub relpersistence: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "6")]
+    pub alias: ::core::option::Option<Alias>,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TableFunc {
+    #[prost(enumeration = "TableFuncType", tag = "1")]
+    pub functype: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub ns_uris: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub ns_names: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub docexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub rowexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "6")]
+    pub colnames: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "7")]
+    pub coltypes: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "8")]
+    pub coltypmods: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "9")]
+    pub colcollations: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "10")]
+    pub colexprs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "11")]
+    pub coldefexprs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "12")]
+    pub colvalexprs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "13")]
+    pub passingvalexprs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint64, repeated, tag = "14")]
+    pub notnulls: ::prost::alloc::vec::Vec<u64>,
+    #[prost(message, optional, boxed, tag = "15")]
+    pub plan: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "16")]
+    pub ordinalitycol: i32,
+    #[prost(int32, tag = "17")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct IntoClause {
+    #[prost(message, optional, tag = "1")]
+    pub rel: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub col_names: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "3")]
+    pub access_method: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "4")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "OnCommitAction", tag = "5")]
+    pub on_commit: i32,
+    #[prost(string, tag = "6")]
+    pub table_space_name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "7")]
+    pub view_query: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(bool, tag = "8")]
+    pub skip_data: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct Var {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "2")]
+    pub varno: i32,
+    #[prost(int32, tag = "3")]
+    pub varattno: i32,
+    #[prost(uint32, tag = "4")]
+    pub vartype: u32,
+    #[prost(int32, tag = "5")]
+    pub vartypmod: i32,
+    #[prost(uint32, tag = "6")]
+    pub varcollid: u32,
+    #[prost(uint64, repeated, tag = "7")]
+    pub varnullingrels: ::prost::alloc::vec::Vec<u64>,
+    #[prost(uint32, tag = "8")]
+    pub varlevelsup: u32,
+    #[prost(int32, tag = "9")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct Param {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "ParamKind", tag = "2")]
+    pub paramkind: i32,
+    #[prost(int32, tag = "3")]
+    pub paramid: i32,
+    #[prost(uint32, tag = "4")]
+    pub paramtype: u32,
+    #[prost(int32, tag = "5")]
+    pub paramtypmod: i32,
+    #[prost(uint32, tag = "6")]
+    pub paramcollid: u32,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct Aggref {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub aggfnoid: u32,
+    #[prost(uint32, tag = "3")]
+    pub aggtype: u32,
+    #[prost(uint32, tag = "4")]
+    pub aggcollid: u32,
+    #[prost(uint32, tag = "5")]
+    pub inputcollid: u32,
+    #[prost(message, repeated, tag = "6")]
+    pub aggargtypes: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "7")]
+    pub aggdirectargs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "8")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "9")]
+    pub aggorder: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "10")]
+    pub aggdistinct: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "11")]
+    pub aggfilter: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(bool, tag = "12")]
+    pub aggstar: bool,
+    #[prost(bool, tag = "13")]
+    pub aggvariadic: bool,
+    #[prost(string, tag = "14")]
+    pub aggkind: ::prost::alloc::string::String,
+    #[prost(uint32, tag = "15")]
+    pub agglevelsup: u32,
+    #[prost(enumeration = "AggSplit", tag = "16")]
+    pub aggsplit: i32,
+    #[prost(int32, tag = "17")]
+    pub aggno: i32,
+    #[prost(int32, tag = "18")]
+    pub aggtransno: i32,
+    #[prost(int32, tag = "19")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct GroupingFunc {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "2")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub refs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint32, tag = "4")]
+    pub agglevelsup: u32,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct WindowFunc {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub winfnoid: u32,
+    #[prost(uint32, tag = "3")]
+    pub wintype: u32,
+    #[prost(uint32, tag = "4")]
+    pub wincollid: u32,
+    #[prost(uint32, tag = "5")]
+    pub inputcollid: u32,
+    #[prost(message, repeated, tag = "6")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "7")]
+    pub aggfilter: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "8")]
+    pub run_condition: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint32, tag = "9")]
+    pub winref: u32,
+    #[prost(bool, tag = "10")]
+    pub winstar: bool,
+    #[prost(bool, tag = "11")]
+    pub winagg: bool,
+    #[prost(int32, tag = "12")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct WindowFuncRunCondition {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub opno: u32,
+    #[prost(uint32, tag = "3")]
+    pub inputcollid: u32,
+    #[prost(bool, tag = "4")]
+    pub wfunc_left: bool,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MergeSupportFunc {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub msftype: u32,
+    #[prost(uint32, tag = "3")]
+    pub msfcollid: u32,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SubscriptingRef {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub refcontainertype: u32,
+    #[prost(uint32, tag = "3")]
+    pub refelemtype: u32,
+    #[prost(uint32, tag = "4")]
+    pub refrestype: u32,
+    #[prost(int32, tag = "5")]
+    pub reftypmod: i32,
+    #[prost(uint32, tag = "6")]
+    pub refcollid: u32,
+    #[prost(message, repeated, tag = "7")]
+    pub refupperindexpr: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "8")]
+    pub reflowerindexpr: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "9")]
+    pub refexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "10")]
+    pub refassgnexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct FuncExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub funcid: u32,
+    #[prost(uint32, tag = "3")]
+    pub funcresulttype: u32,
+    #[prost(bool, tag = "4")]
+    pub funcretset: bool,
+    #[prost(bool, tag = "5")]
+    pub funcvariadic: bool,
+    #[prost(enumeration = "CoercionForm", tag = "6")]
+    pub funcformat: i32,
+    #[prost(uint32, tag = "7")]
+    pub funccollid: u32,
+    #[prost(uint32, tag = "8")]
+    pub inputcollid: u32,
+    #[prost(message, repeated, tag = "9")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "10")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct NamedArgExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "3")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(int32, tag = "4")]
+    pub argnumber: i32,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct OpExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub opno: u32,
+    #[prost(uint32, tag = "3")]
+    pub opresulttype: u32,
+    #[prost(bool, tag = "4")]
+    pub opretset: bool,
+    #[prost(uint32, tag = "5")]
+    pub opcollid: u32,
+    #[prost(uint32, tag = "6")]
+    pub inputcollid: u32,
+    #[prost(message, repeated, tag = "7")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "8")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DistinctExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub opno: u32,
+    #[prost(uint32, tag = "3")]
+    pub opresulttype: u32,
+    #[prost(bool, tag = "4")]
+    pub opretset: bool,
+    #[prost(uint32, tag = "5")]
+    pub opcollid: u32,
+    #[prost(uint32, tag = "6")]
+    pub inputcollid: u32,
+    #[prost(message, repeated, tag = "7")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "8")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct NullIfExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub opno: u32,
+    #[prost(uint32, tag = "3")]
+    pub opresulttype: u32,
+    #[prost(bool, tag = "4")]
+    pub opretset: bool,
+    #[prost(uint32, tag = "5")]
+    pub opcollid: u32,
+    #[prost(uint32, tag = "6")]
+    pub inputcollid: u32,
+    #[prost(message, repeated, tag = "7")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "8")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ScalarArrayOpExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub opno: u32,
+    #[prost(bool, tag = "3")]
+    pub use_or: bool,
+    #[prost(uint32, tag = "4")]
+    pub inputcollid: u32,
+    #[prost(message, repeated, tag = "5")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "6")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct BoolExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "BoolExprType", tag = "2")]
+    pub boolop: i32,
+    #[prost(message, repeated, tag = "3")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SubLink {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "SubLinkType", tag = "2")]
+    pub sub_link_type: i32,
+    #[prost(int32, tag = "3")]
+    pub sub_link_id: i32,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub testexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "5")]
+    pub oper_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub subselect: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SubPlan {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "SubLinkType", tag = "2")]
+    pub sub_link_type: i32,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub testexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "4")]
+    pub param_ids: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "5")]
+    pub plan_id: i32,
+    #[prost(string, tag = "6")]
+    pub plan_name: ::prost::alloc::string::String,
+    #[prost(uint32, tag = "7")]
+    pub first_col_type: u32,
+    #[prost(int32, tag = "8")]
+    pub first_col_typmod: i32,
+    #[prost(uint32, tag = "9")]
+    pub first_col_collation: u32,
+    #[prost(bool, tag = "10")]
+    pub use_hash_table: bool,
+    #[prost(bool, tag = "11")]
+    pub unknown_eq_false: bool,
+    #[prost(bool, tag = "12")]
+    pub parallel_safe: bool,
+    #[prost(message, repeated, tag = "13")]
+    pub set_param: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "14")]
+    pub par_param: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "15")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(double, tag = "16")]
+    pub startup_cost: f64,
+    #[prost(double, tag = "17")]
+    pub per_call_cost: f64,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlternativeSubPlan {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "2")]
+    pub subplans: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct FieldSelect {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "3")]
+    pub fieldnum: i32,
+    #[prost(uint32, tag = "4")]
+    pub resulttype: u32,
+    #[prost(int32, tag = "5")]
+    pub resulttypmod: i32,
+    #[prost(uint32, tag = "6")]
+    pub resultcollid: u32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct FieldStore {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "3")]
+    pub newvals: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub fieldnums: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint32, tag = "5")]
+    pub resulttype: u32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RelabelType {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "3")]
+    pub resulttype: u32,
+    #[prost(int32, tag = "4")]
+    pub resulttypmod: i32,
+    #[prost(uint32, tag = "5")]
+    pub resultcollid: u32,
+    #[prost(enumeration = "CoercionForm", tag = "6")]
+    pub relabelformat: i32,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CoerceViaIo {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "3")]
+    pub resulttype: u32,
+    #[prost(uint32, tag = "4")]
+    pub resultcollid: u32,
+    #[prost(enumeration = "CoercionForm", tag = "5")]
+    pub coerceformat: i32,
+    #[prost(int32, tag = "6")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ArrayCoerceExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub elemexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "4")]
+    pub resulttype: u32,
+    #[prost(int32, tag = "5")]
+    pub resulttypmod: i32,
+    #[prost(uint32, tag = "6")]
+    pub resultcollid: u32,
+    #[prost(enumeration = "CoercionForm", tag = "7")]
+    pub coerceformat: i32,
+    #[prost(int32, tag = "8")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ConvertRowtypeExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "3")]
+    pub resulttype: u32,
+    #[prost(enumeration = "CoercionForm", tag = "4")]
+    pub convertformat: i32,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CollateExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "3")]
+    pub coll_oid: u32,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CaseExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub casetype: u32,
+    #[prost(uint32, tag = "3")]
+    pub casecollid: u32,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "5")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub defresult: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CaseWhen {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub result: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CaseTestExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub type_id: u32,
+    #[prost(int32, tag = "3")]
+    pub type_mod: i32,
+    #[prost(uint32, tag = "4")]
+    pub collation: u32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ArrayExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub array_typeid: u32,
+    #[prost(uint32, tag = "3")]
+    pub array_collid: u32,
+    #[prost(uint32, tag = "4")]
+    pub element_typeid: u32,
+    #[prost(message, repeated, tag = "5")]
+    pub elements: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "6")]
+    pub multidims: bool,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RowExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "2")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint32, tag = "3")]
+    pub row_typeid: u32,
+    #[prost(enumeration = "CoercionForm", tag = "4")]
+    pub row_format: i32,
+    #[prost(message, repeated, tag = "5")]
+    pub colnames: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "6")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RowCompareExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "RowCompareType", tag = "2")]
+    pub rctype: i32,
+    #[prost(message, repeated, tag = "3")]
+    pub opnos: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub opfamilies: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub inputcollids: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub largs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "7")]
+    pub rargs: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CoalesceExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub coalescetype: u32,
+    #[prost(uint32, tag = "3")]
+    pub coalescecollid: u32,
+    #[prost(message, repeated, tag = "4")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MinMaxExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub minmaxtype: u32,
+    #[prost(uint32, tag = "3")]
+    pub minmaxcollid: u32,
+    #[prost(uint32, tag = "4")]
+    pub inputcollid: u32,
+    #[prost(enumeration = "MinMaxOp", tag = "5")]
+    pub op: i32,
+    #[prost(message, repeated, tag = "6")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SqlValueFunction {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "SqlValueFunctionOp", tag = "2")]
+    pub op: i32,
+    #[prost(uint32, tag = "3")]
+    pub r#type: u32,
+    #[prost(int32, tag = "4")]
+    pub typmod: i32,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct XmlExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "XmlExprOp", tag = "2")]
+    pub op: i32,
+    #[prost(string, tag = "3")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "4")]
+    pub named_args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub arg_names: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "XmlOptionType", tag = "7")]
+    pub xmloption: i32,
+    #[prost(bool, tag = "8")]
+    pub indent: bool,
+    #[prost(uint32, tag = "9")]
+    pub r#type: u32,
+    #[prost(int32, tag = "10")]
+    pub typmod: i32,
+    #[prost(int32, tag = "11")]
+    pub location: i32,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct JsonFormat {
+    #[prost(enumeration = "JsonFormatType", tag = "1")]
+    pub format_type: i32,
+    #[prost(enumeration = "JsonEncoding", tag = "2")]
+    pub encoding: i32,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct JsonReturning {
+    #[prost(message, optional, tag = "1")]
+    pub format: ::core::option::Option<JsonFormat>,
+    #[prost(uint32, tag = "2")]
+    pub typid: u32,
+    #[prost(int32, tag = "3")]
+    pub typmod: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonValueExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub raw_expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub formatted_expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "3")]
+    pub format: ::core::option::Option<JsonFormat>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonConstructorExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "JsonConstructorType", tag = "2")]
+    pub r#type: i32,
+    #[prost(message, repeated, tag = "3")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub func: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub coercion: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "6")]
+    pub returning: ::core::option::Option<JsonReturning>,
+    #[prost(bool, tag = "7")]
+    pub absent_on_null: bool,
+    #[prost(bool, tag = "8")]
+    pub unique: bool,
+    #[prost(int32, tag = "9")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonIsPredicate {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "2")]
+    pub format: ::core::option::Option<JsonFormat>,
+    #[prost(enumeration = "JsonValueType", tag = "3")]
+    pub item_type: i32,
+    #[prost(bool, tag = "4")]
+    pub unique_keys: bool,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonBehavior {
+    #[prost(enumeration = "JsonBehaviorType", tag = "1")]
+    pub btype: i32,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(bool, tag = "3")]
+    pub coerce: bool,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "JsonExprOp", tag = "2")]
+    pub op: i32,
+    #[prost(string, tag = "3")]
+    pub column_name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub formatted_expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "5")]
+    pub format: ::core::option::Option<JsonFormat>,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub path_spec: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "7")]
+    pub returning: ::core::option::Option<JsonReturning>,
+    #[prost(message, repeated, tag = "8")]
+    pub passing_names: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "9")]
+    pub passing_values: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "10")]
+    pub on_empty: ::core::option::Option<::prost::alloc::boxed::Box<JsonBehavior>>,
+    #[prost(message, optional, boxed, tag = "11")]
+    pub on_error: ::core::option::Option<::prost::alloc::boxed::Box<JsonBehavior>>,
+    #[prost(bool, tag = "12")]
+    pub use_io_coercion: bool,
+    #[prost(bool, tag = "13")]
+    pub use_json_coercion: bool,
+    #[prost(enumeration = "JsonWrapper", tag = "14")]
+    pub wrapper: i32,
+    #[prost(bool, tag = "15")]
+    pub omit_quotes: bool,
+    #[prost(uint32, tag = "16")]
+    pub collation: u32,
+    #[prost(int32, tag = "17")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonTablePath {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonTablePathScan {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub plan: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "2")]
+    pub path: ::core::option::Option<JsonTablePath>,
+    #[prost(bool, tag = "3")]
+    pub error_on_error: bool,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub child: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "5")]
+    pub col_min: i32,
+    #[prost(int32, tag = "6")]
+    pub col_max: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonTableSiblingJoin {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub plan: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub lplan: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub rplan: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct NullTest {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "NullTestType", tag = "3")]
+    pub nulltesttype: i32,
+    #[prost(bool, tag = "4")]
+    pub argisrow: bool,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct BooleanTest {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "BoolTestType", tag = "3")]
+    pub booltesttype: i32,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MergeAction {
+    #[prost(enumeration = "MergeMatchKind", tag = "1")]
+    pub match_kind: i32,
+    #[prost(enumeration = "CmdType", tag = "2")]
+    pub command_type: i32,
+    #[prost(enumeration = "OverridingKind", tag = "3")]
+    pub r#override: i32,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub qual: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "5")]
+    pub target_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub update_colnos: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CoerceToDomain {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "3")]
+    pub resulttype: u32,
+    #[prost(int32, tag = "4")]
+    pub resulttypmod: i32,
+    #[prost(uint32, tag = "5")]
+    pub resultcollid: u32,
+    #[prost(enumeration = "CoercionForm", tag = "6")]
+    pub coercionformat: i32,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CoerceToDomainValue {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub type_id: u32,
+    #[prost(int32, tag = "3")]
+    pub type_mod: i32,
+    #[prost(uint32, tag = "4")]
+    pub collation: u32,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SetToDefault {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub type_id: u32,
+    #[prost(int32, tag = "3")]
+    pub type_mod: i32,
+    #[prost(uint32, tag = "4")]
+    pub collation: u32,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CurrentOfExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub cvarno: u32,
+    #[prost(string, tag = "3")]
+    pub cursor_name: ::prost::alloc::string::String,
+    #[prost(int32, tag = "4")]
+    pub cursor_param: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct NextValueExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "2")]
+    pub seqid: u32,
+    #[prost(uint32, tag = "3")]
+    pub type_id: u32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct InferenceElem {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "3")]
+    pub infercollid: u32,
+    #[prost(uint32, tag = "4")]
+    pub inferopclass: u32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TargetEntry {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub xpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "3")]
+    pub resno: i32,
+    #[prost(string, tag = "4")]
+    pub resname: ::prost::alloc::string::String,
+    #[prost(uint32, tag = "5")]
+    pub ressortgroupref: u32,
+    #[prost(uint32, tag = "6")]
+    pub resorigtbl: u32,
+    #[prost(int32, tag = "7")]
+    pub resorigcol: i32,
+    #[prost(bool, tag = "8")]
+    pub resjunk: bool,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct RangeTblRef {
+    #[prost(int32, tag = "1")]
+    pub rtindex: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JoinExpr {
+    #[prost(enumeration = "JoinType", tag = "1")]
+    pub jointype: i32,
+    #[prost(bool, tag = "2")]
+    pub is_natural: bool,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub larg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub rarg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "5")]
+    pub using_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "6")]
+    pub join_using_alias: ::core::option::Option<Alias>,
+    #[prost(message, optional, boxed, tag = "7")]
+    pub quals: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "8")]
+    pub alias: ::core::option::Option<Alias>,
+    #[prost(int32, tag = "9")]
+    pub rtindex: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct FromExpr {
+    #[prost(message, repeated, tag = "1")]
+    pub fromlist: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub quals: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct OnConflictExpr {
+    #[prost(enumeration = "OnConflictAction", tag = "1")]
+    pub action: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub arbiter_elems: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub arbiter_where: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "4")]
+    pub constraint: u32,
+    #[prost(message, repeated, tag = "5")]
+    pub on_conflict_set: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub on_conflict_where: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "7")]
+    pub excl_rel_index: i32,
+    #[prost(message, repeated, tag = "8")]
+    pub excl_rel_tlist: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct Query {
+    #[prost(enumeration = "CmdType", tag = "1")]
+    pub command_type: i32,
+    #[prost(enumeration = "QuerySource", tag = "2")]
+    pub query_source: i32,
+    #[prost(bool, tag = "3")]
+    pub can_set_tag: bool,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub utility_stmt: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "5")]
+    pub result_relation: i32,
+    #[prost(bool, tag = "6")]
+    pub has_aggs: bool,
+    #[prost(bool, tag = "7")]
+    pub has_window_funcs: bool,
+    #[prost(bool, tag = "8")]
+    pub has_target_srfs: bool,
+    #[prost(bool, tag = "9")]
+    pub has_sub_links: bool,
+    #[prost(bool, tag = "10")]
+    pub has_distinct_on: bool,
+    #[prost(bool, tag = "11")]
+    pub has_recursive: bool,
+    #[prost(bool, tag = "12")]
+    pub has_modifying_cte: bool,
+    #[prost(bool, tag = "13")]
+    pub has_for_update: bool,
+    #[prost(bool, tag = "14")]
+    pub has_row_security: bool,
+    #[prost(bool, tag = "15")]
+    pub is_return: bool,
+    #[prost(message, repeated, tag = "16")]
+    pub cte_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "17")]
+    pub rtable: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "18")]
+    pub rteperminfos: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "19")]
+    pub jointree: ::core::option::Option<::prost::alloc::boxed::Box<FromExpr>>,
+    #[prost(message, repeated, tag = "20")]
+    pub merge_action_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "21")]
+    pub merge_target_relation: i32,
+    #[prost(message, optional, boxed, tag = "22")]
+    pub merge_join_condition: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "23")]
+    pub target_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "OverridingKind", tag = "24")]
+    pub r#override: i32,
+    #[prost(message, optional, boxed, tag = "25")]
+    pub on_conflict: ::core::option::Option<::prost::alloc::boxed::Box<OnConflictExpr>>,
+    #[prost(message, repeated, tag = "26")]
+    pub returning_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "27")]
+    pub group_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "28")]
+    pub group_distinct: bool,
+    #[prost(message, repeated, tag = "29")]
+    pub grouping_sets: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "30")]
+    pub having_qual: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "31")]
+    pub window_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "32")]
+    pub distinct_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "33")]
+    pub sort_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "34")]
+    pub limit_offset: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "35")]
+    pub limit_count: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "LimitOption", tag = "36")]
+    pub limit_option: i32,
+    #[prost(message, repeated, tag = "37")]
+    pub row_marks: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "38")]
+    pub set_operations: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "39")]
+    pub constraint_deps: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "40")]
+    pub with_check_options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "41")]
+    pub stmt_location: i32,
+    #[prost(int32, tag = "42")]
+    pub stmt_len: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TypeName {
+    #[prost(message, repeated, tag = "1")]
+    pub names: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint32, tag = "2")]
+    pub type_oid: u32,
+    #[prost(bool, tag = "3")]
+    pub setof: bool,
+    #[prost(bool, tag = "4")]
+    pub pct_type: bool,
+    #[prost(message, repeated, tag = "5")]
+    pub typmods: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "6")]
+    pub typemod: i32,
+    #[prost(message, repeated, tag = "7")]
+    pub array_bounds: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "8")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ColumnRef {
+    #[prost(message, repeated, tag = "1")]
+    pub fields: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "2")]
+    pub location: i32,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct ParamRef {
+    #[prost(int32, tag = "1")]
+    pub number: i32,
+    #[prost(int32, tag = "2")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AExpr {
+    #[prost(enumeration = "AExprKind", tag = "1")]
+    pub kind: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub lexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub rexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TypeCast {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "2")]
+    pub type_name: ::core::option::Option<TypeName>,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CollateClause {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "2")]
+    pub collname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RoleSpec {
+    #[prost(enumeration = "RoleSpecType", tag = "1")]
+    pub roletype: i32,
+    #[prost(string, tag = "2")]
+    pub rolename: ::prost::alloc::string::String,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct FuncCall {
+    #[prost(message, repeated, tag = "1")]
+    pub funcname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub agg_order: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub agg_filter: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub over: ::core::option::Option<::prost::alloc::boxed::Box<WindowDef>>,
+    #[prost(bool, tag = "6")]
+    pub agg_within_group: bool,
+    #[prost(bool, tag = "7")]
+    pub agg_star: bool,
+    #[prost(bool, tag = "8")]
+    pub agg_distinct: bool,
+    #[prost(bool, tag = "9")]
+    pub func_variadic: bool,
+    #[prost(enumeration = "CoercionForm", tag = "10")]
+    pub funcformat: i32,
+    #[prost(int32, tag = "11")]
+    pub location: i32,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct AStar {}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AIndices {
+    #[prost(bool, tag = "1")]
+    pub is_slice: bool,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub lidx: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub uidx: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AIndirection {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "2")]
+    pub indirection: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AArrayExpr {
+    #[prost(message, repeated, tag = "1")]
+    pub elements: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "2")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ResTarget {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub indirection: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub val: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MultiAssignRef {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub source: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "2")]
+    pub colno: i32,
+    #[prost(int32, tag = "3")]
+    pub ncolumns: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SortBy {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub node: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "SortByDir", tag = "2")]
+    pub sortby_dir: i32,
+    #[prost(enumeration = "SortByNulls", tag = "3")]
+    pub sortby_nulls: i32,
+    #[prost(message, repeated, tag = "4")]
+    pub use_op: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct WindowDef {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub refname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub partition_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub order_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "5")]
+    pub frame_options: i32,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub start_offset: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "7")]
+    pub end_offset: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "8")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RangeSubselect {
+    #[prost(bool, tag = "1")]
+    pub lateral: bool,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub subquery: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "3")]
+    pub alias: ::core::option::Option<Alias>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RangeFunction {
+    #[prost(bool, tag = "1")]
+    pub lateral: bool,
+    #[prost(bool, tag = "2")]
+    pub ordinality: bool,
+    #[prost(bool, tag = "3")]
+    pub is_rowsfrom: bool,
+    #[prost(message, repeated, tag = "4")]
+    pub functions: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "5")]
+    pub alias: ::core::option::Option<Alias>,
+    #[prost(message, repeated, tag = "6")]
+    pub coldeflist: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RangeTableFunc {
+    #[prost(bool, tag = "1")]
+    pub lateral: bool,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub docexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub rowexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "4")]
+    pub namespaces: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub columns: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "6")]
+    pub alias: ::core::option::Option<Alias>,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RangeTableFuncCol {
+    #[prost(string, tag = "1")]
+    pub colname: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub type_name: ::core::option::Option<TypeName>,
+    #[prost(bool, tag = "3")]
+    pub for_ordinality: bool,
+    #[prost(bool, tag = "4")]
+    pub is_not_null: bool,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub colexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub coldefexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RangeTableSample {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub relation: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "2")]
+    pub method: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub repeatable: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ColumnDef {
+    #[prost(string, tag = "1")]
+    pub colname: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub type_name: ::core::option::Option<TypeName>,
+    #[prost(string, tag = "3")]
+    pub compression: ::prost::alloc::string::String,
+    #[prost(int32, tag = "4")]
+    pub inhcount: i32,
+    #[prost(bool, tag = "5")]
+    pub is_local: bool,
+    #[prost(bool, tag = "6")]
+    pub is_not_null: bool,
+    #[prost(bool, tag = "7")]
+    pub is_from_type: bool,
+    #[prost(string, tag = "8")]
+    pub storage: ::prost::alloc::string::String,
+    #[prost(string, tag = "9")]
+    pub storage_name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "10")]
+    pub raw_default: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "11")]
+    pub cooked_default: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "12")]
+    pub identity: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "13")]
+    pub identity_sequence: ::core::option::Option<RangeVar>,
+    #[prost(string, tag = "14")]
+    pub generated: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "15")]
+    pub coll_clause: ::core::option::Option<::prost::alloc::boxed::Box<CollateClause>>,
+    #[prost(uint32, tag = "16")]
+    pub coll_oid: u32,
+    #[prost(message, repeated, tag = "17")]
+    pub constraints: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "18")]
+    pub fdwoptions: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "19")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TableLikeClause {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(uint32, tag = "2")]
+    pub options: u32,
+    #[prost(uint32, tag = "3")]
+    pub relation_oid: u32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct IndexElem {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "3")]
+    pub indexcolname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "4")]
+    pub collation: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub opclass: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub opclassopts: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "SortByDir", tag = "7")]
+    pub ordering: i32,
+    #[prost(enumeration = "SortByNulls", tag = "8")]
+    pub nulls_ordering: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DefElem {
+    #[prost(string, tag = "1")]
+    pub defnamespace: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub defname: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "DefElemAction", tag = "4")]
+    pub defaction: i32,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct LockingClause {
+    #[prost(message, repeated, tag = "1")]
+    pub locked_rels: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "LockClauseStrength", tag = "2")]
+    pub strength: i32,
+    #[prost(enumeration = "LockWaitPolicy", tag = "3")]
+    pub wait_policy: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct XmlSerialize {
+    #[prost(enumeration = "XmlOptionType", tag = "1")]
+    pub xmloption: i32,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "3")]
+    pub type_name: ::core::option::Option<TypeName>,
+    #[prost(bool, tag = "4")]
+    pub indent: bool,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PartitionElem {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "3")]
+    pub collation: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub opclass: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PartitionSpec {
+    #[prost(enumeration = "PartitionStrategy", tag = "1")]
+    pub strategy: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub part_params: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PartitionBoundSpec {
+    #[prost(string, tag = "1")]
+    pub strategy: ::prost::alloc::string::String,
+    #[prost(bool, tag = "2")]
+    pub is_default: bool,
+    #[prost(int32, tag = "3")]
+    pub modulus: i32,
+    #[prost(int32, tag = "4")]
+    pub remainder: i32,
+    #[prost(message, repeated, tag = "5")]
+    pub listdatums: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub lowerdatums: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "7")]
+    pub upperdatums: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "8")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PartitionRangeDatum {
+    #[prost(enumeration = "PartitionRangeDatumKind", tag = "1")]
+    pub kind: i32,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub value: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct SinglePartitionSpec {}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PartitionCmd {
+    #[prost(message, optional, tag = "1")]
+    pub name: ::core::option::Option<RangeVar>,
+    #[prost(message, optional, tag = "2")]
+    pub bound: ::core::option::Option<PartitionBoundSpec>,
+    #[prost(bool, tag = "3")]
+    pub concurrent: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RangeTblEntry {
+    #[prost(message, optional, tag = "1")]
+    pub alias: ::core::option::Option<Alias>,
+    #[prost(message, optional, tag = "2")]
+    pub eref: ::core::option::Option<Alias>,
+    #[prost(enumeration = "RteKind", tag = "3")]
+    pub rtekind: i32,
+    #[prost(uint32, tag = "4")]
+    pub relid: u32,
+    #[prost(bool, tag = "5")]
+    pub inh: bool,
+    #[prost(string, tag = "6")]
+    pub relkind: ::prost::alloc::string::String,
+    #[prost(int32, tag = "7")]
+    pub rellockmode: i32,
+    #[prost(uint32, tag = "8")]
+    pub perminfoindex: u32,
+    #[prost(message, optional, boxed, tag = "9")]
+    pub tablesample: ::core::option::Option<
+        ::prost::alloc::boxed::Box<TableSampleClause>,
+    >,
+    #[prost(message, optional, boxed, tag = "10")]
+    pub subquery: ::core::option::Option<::prost::alloc::boxed::Box<Query>>,
+    #[prost(bool, tag = "11")]
+    pub security_barrier: bool,
+    #[prost(enumeration = "JoinType", tag = "12")]
+    pub jointype: i32,
+    #[prost(int32, tag = "13")]
+    pub joinmergedcols: i32,
+    #[prost(message, repeated, tag = "14")]
+    pub joinaliasvars: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "15")]
+    pub joinleftcols: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "16")]
+    pub joinrightcols: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "17")]
+    pub join_using_alias: ::core::option::Option<Alias>,
+    #[prost(message, repeated, tag = "18")]
+    pub functions: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "19")]
+    pub funcordinality: bool,
+    #[prost(message, optional, boxed, tag = "20")]
+    pub tablefunc: ::core::option::Option<::prost::alloc::boxed::Box<TableFunc>>,
+    #[prost(message, repeated, tag = "21")]
+    pub values_lists: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "22")]
+    pub ctename: ::prost::alloc::string::String,
+    #[prost(uint32, tag = "23")]
+    pub ctelevelsup: u32,
+    #[prost(bool, tag = "24")]
+    pub self_reference: bool,
+    #[prost(message, repeated, tag = "25")]
+    pub coltypes: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "26")]
+    pub coltypmods: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "27")]
+    pub colcollations: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "28")]
+    pub enrname: ::prost::alloc::string::String,
+    #[prost(double, tag = "29")]
+    pub enrtuples: f64,
+    #[prost(bool, tag = "30")]
+    pub lateral: bool,
+    #[prost(bool, tag = "31")]
+    pub in_from_cl: bool,
+    #[prost(message, repeated, tag = "32")]
+    pub security_quals: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RtePermissionInfo {
+    #[prost(uint32, tag = "1")]
+    pub relid: u32,
+    #[prost(bool, tag = "2")]
+    pub inh: bool,
+    #[prost(uint64, tag = "3")]
+    pub required_perms: u64,
+    #[prost(uint32, tag = "4")]
+    pub check_as_user: u32,
+    #[prost(uint64, repeated, tag = "5")]
+    pub selected_cols: ::prost::alloc::vec::Vec<u64>,
+    #[prost(uint64, repeated, tag = "6")]
+    pub inserted_cols: ::prost::alloc::vec::Vec<u64>,
+    #[prost(uint64, repeated, tag = "7")]
+    pub updated_cols: ::prost::alloc::vec::Vec<u64>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RangeTblFunction {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub funcexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "2")]
+    pub funccolcount: i32,
+    #[prost(message, repeated, tag = "3")]
+    pub funccolnames: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub funccoltypes: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub funccoltypmods: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub funccolcollations: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint64, repeated, tag = "7")]
+    pub funcparams: ::prost::alloc::vec::Vec<u64>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TableSampleClause {
+    #[prost(uint32, tag = "1")]
+    pub tsmhandler: u32,
+    #[prost(message, repeated, tag = "2")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub repeatable: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct WithCheckOption {
+    #[prost(enumeration = "WcoKind", tag = "1")]
+    pub kind: i32,
+    #[prost(string, tag = "2")]
+    pub relname: ::prost::alloc::string::String,
+    #[prost(string, tag = "3")]
+    pub polname: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub qual: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(bool, tag = "5")]
+    pub cascaded: bool,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct SortGroupClause {
+    #[prost(uint32, tag = "1")]
+    pub tle_sort_group_ref: u32,
+    #[prost(uint32, tag = "2")]
+    pub eqop: u32,
+    #[prost(uint32, tag = "3")]
+    pub sortop: u32,
+    #[prost(bool, tag = "4")]
+    pub nulls_first: bool,
+    #[prost(bool, tag = "5")]
+    pub hashable: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct GroupingSet {
+    #[prost(enumeration = "GroupingSetKind", tag = "1")]
+    pub kind: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub content: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct WindowClause {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub refname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub partition_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub order_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "5")]
+    pub frame_options: i32,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub start_offset: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "7")]
+    pub end_offset: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(uint32, tag = "8")]
+    pub start_in_range_func: u32,
+    #[prost(uint32, tag = "9")]
+    pub end_in_range_func: u32,
+    #[prost(uint32, tag = "10")]
+    pub in_range_coll: u32,
+    #[prost(bool, tag = "11")]
+    pub in_range_asc: bool,
+    #[prost(bool, tag = "12")]
+    pub in_range_nulls_first: bool,
+    #[prost(uint32, tag = "13")]
+    pub winref: u32,
+    #[prost(bool, tag = "14")]
+    pub copied_order: bool,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct RowMarkClause {
+    #[prost(uint32, tag = "1")]
+    pub rti: u32,
+    #[prost(enumeration = "LockClauseStrength", tag = "2")]
+    pub strength: i32,
+    #[prost(enumeration = "LockWaitPolicy", tag = "3")]
+    pub wait_policy: i32,
+    #[prost(bool, tag = "4")]
+    pub pushed_down: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct WithClause {
+    #[prost(message, repeated, tag = "1")]
+    pub ctes: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "2")]
+    pub recursive: bool,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct InferClause {
+    #[prost(message, repeated, tag = "1")]
+    pub index_elems: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "3")]
+    pub conname: ::prost::alloc::string::String,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct OnConflictClause {
+    #[prost(enumeration = "OnConflictAction", tag = "1")]
+    pub action: i32,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub infer: ::core::option::Option<::prost::alloc::boxed::Box<InferClause>>,
+    #[prost(message, repeated, tag = "3")]
+    pub target_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CteSearchClause {
+    #[prost(message, repeated, tag = "1")]
+    pub search_col_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "2")]
+    pub search_breadth_first: bool,
+    #[prost(string, tag = "3")]
+    pub search_seq_column: ::prost::alloc::string::String,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CteCycleClause {
+    #[prost(message, repeated, tag = "1")]
+    pub cycle_col_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "2")]
+    pub cycle_mark_column: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub cycle_mark_value: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub cycle_mark_default: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "5")]
+    pub cycle_path_column: ::prost::alloc::string::String,
+    #[prost(int32, tag = "6")]
+    pub location: i32,
+    #[prost(uint32, tag = "7")]
+    pub cycle_mark_type: u32,
+    #[prost(int32, tag = "8")]
+    pub cycle_mark_typmod: i32,
+    #[prost(uint32, tag = "9")]
+    pub cycle_mark_collation: u32,
+    #[prost(uint32, tag = "10")]
+    pub cycle_mark_neop: u32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CommonTableExpr {
+    #[prost(string, tag = "1")]
+    pub ctename: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub aliascolnames: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "CteMaterialize", tag = "3")]
+    pub ctematerialized: i32,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub ctequery: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "5")]
+    pub search_clause: ::core::option::Option<CteSearchClause>,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub cycle_clause: ::core::option::Option<::prost::alloc::boxed::Box<CteCycleClause>>,
+    #[prost(int32, tag = "7")]
+    pub location: i32,
+    #[prost(bool, tag = "8")]
+    pub cterecursive: bool,
+    #[prost(int32, tag = "9")]
+    pub cterefcount: i32,
+    #[prost(message, repeated, tag = "10")]
+    pub ctecolnames: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "11")]
+    pub ctecoltypes: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "12")]
+    pub ctecoltypmods: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "13")]
+    pub ctecolcollations: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MergeWhenClause {
+    #[prost(enumeration = "MergeMatchKind", tag = "1")]
+    pub match_kind: i32,
+    #[prost(enumeration = "CmdType", tag = "2")]
+    pub command_type: i32,
+    #[prost(enumeration = "OverridingKind", tag = "3")]
+    pub r#override: i32,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub condition: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "5")]
+    pub target_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub values: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TriggerTransition {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(bool, tag = "2")]
+    pub is_new: bool,
+    #[prost(bool, tag = "3")]
+    pub is_table: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonOutput {
+    #[prost(message, optional, tag = "1")]
+    pub type_name: ::core::option::Option<TypeName>,
+    #[prost(message, optional, tag = "2")]
+    pub returning: ::core::option::Option<JsonReturning>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonArgument {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub val: ::core::option::Option<::prost::alloc::boxed::Box<JsonValueExpr>>,
+    #[prost(string, tag = "2")]
+    pub name: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonFuncExpr {
+    #[prost(enumeration = "JsonExprOp", tag = "1")]
+    pub op: i32,
+    #[prost(string, tag = "2")]
+    pub column_name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub context_item: ::core::option::Option<::prost::alloc::boxed::Box<JsonValueExpr>>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub pathspec: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "5")]
+    pub passing: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "6")]
+    pub output: ::core::option::Option<JsonOutput>,
+    #[prost(message, optional, boxed, tag = "7")]
+    pub on_empty: ::core::option::Option<::prost::alloc::boxed::Box<JsonBehavior>>,
+    #[prost(message, optional, boxed, tag = "8")]
+    pub on_error: ::core::option::Option<::prost::alloc::boxed::Box<JsonBehavior>>,
+    #[prost(enumeration = "JsonWrapper", tag = "9")]
+    pub wrapper: i32,
+    #[prost(enumeration = "JsonQuotes", tag = "10")]
+    pub quotes: i32,
+    #[prost(int32, tag = "11")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonTablePathSpec {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub string: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "2")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(int32, tag = "3")]
+    pub name_location: i32,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonTable {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub context_item: ::core::option::Option<::prost::alloc::boxed::Box<JsonValueExpr>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub pathspec: ::core::option::Option<::prost::alloc::boxed::Box<JsonTablePathSpec>>,
+    #[prost(message, repeated, tag = "3")]
+    pub passing: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub columns: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub on_error: ::core::option::Option<::prost::alloc::boxed::Box<JsonBehavior>>,
+    #[prost(message, optional, tag = "6")]
+    pub alias: ::core::option::Option<Alias>,
+    #[prost(bool, tag = "7")]
+    pub lateral: bool,
+    #[prost(int32, tag = "8")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonTableColumn {
+    #[prost(enumeration = "JsonTableColumnType", tag = "1")]
+    pub coltype: i32,
+    #[prost(string, tag = "2")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "3")]
+    pub type_name: ::core::option::Option<TypeName>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub pathspec: ::core::option::Option<::prost::alloc::boxed::Box<JsonTablePathSpec>>,
+    #[prost(message, optional, tag = "5")]
+    pub format: ::core::option::Option<JsonFormat>,
+    #[prost(enumeration = "JsonWrapper", tag = "6")]
+    pub wrapper: i32,
+    #[prost(enumeration = "JsonQuotes", tag = "7")]
+    pub quotes: i32,
+    #[prost(message, repeated, tag = "8")]
+    pub columns: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "9")]
+    pub on_empty: ::core::option::Option<::prost::alloc::boxed::Box<JsonBehavior>>,
+    #[prost(message, optional, boxed, tag = "10")]
+    pub on_error: ::core::option::Option<::prost::alloc::boxed::Box<JsonBehavior>>,
+    #[prost(int32, tag = "11")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonKeyValue {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub key: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub value: ::core::option::Option<::prost::alloc::boxed::Box<JsonValueExpr>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonParseExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<JsonValueExpr>>,
+    #[prost(message, optional, tag = "2")]
+    pub output: ::core::option::Option<JsonOutput>,
+    #[prost(bool, tag = "3")]
+    pub unique_keys: bool,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonScalarExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "2")]
+    pub output: ::core::option::Option<JsonOutput>,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonSerializeExpr {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<JsonValueExpr>>,
+    #[prost(message, optional, tag = "2")]
+    pub output: ::core::option::Option<JsonOutput>,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonObjectConstructor {
+    #[prost(message, repeated, tag = "1")]
+    pub exprs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "2")]
+    pub output: ::core::option::Option<JsonOutput>,
+    #[prost(bool, tag = "3")]
+    pub absent_on_null: bool,
+    #[prost(bool, tag = "4")]
+    pub unique: bool,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonArrayConstructor {
+    #[prost(message, repeated, tag = "1")]
+    pub exprs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "2")]
+    pub output: ::core::option::Option<JsonOutput>,
+    #[prost(bool, tag = "3")]
+    pub absent_on_null: bool,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonArrayQueryConstructor {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub query: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "2")]
+    pub output: ::core::option::Option<JsonOutput>,
+    #[prost(message, optional, tag = "3")]
+    pub format: ::core::option::Option<JsonFormat>,
+    #[prost(bool, tag = "4")]
+    pub absent_on_null: bool,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonAggConstructor {
+    #[prost(message, optional, tag = "1")]
+    pub output: ::core::option::Option<JsonOutput>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub agg_filter: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "3")]
+    pub agg_order: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub over: ::core::option::Option<::prost::alloc::boxed::Box<WindowDef>>,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonObjectAgg {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub constructor: ::core::option::Option<
+        ::prost::alloc::boxed::Box<JsonAggConstructor>,
+    >,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<JsonKeyValue>>,
+    #[prost(bool, tag = "3")]
+    pub absent_on_null: bool,
+    #[prost(bool, tag = "4")]
+    pub unique: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct JsonArrayAgg {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub constructor: ::core::option::Option<
+        ::prost::alloc::boxed::Box<JsonAggConstructor>,
+    >,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub arg: ::core::option::Option<::prost::alloc::boxed::Box<JsonValueExpr>>,
+    #[prost(bool, tag = "3")]
+    pub absent_on_null: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RawStmt {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub stmt: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(int32, tag = "2")]
+    pub stmt_location: i32,
+    #[prost(int32, tag = "3")]
+    pub stmt_len: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct InsertStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub cols: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub select_stmt: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub on_conflict_clause: ::core::option::Option<
+        ::prost::alloc::boxed::Box<OnConflictClause>,
+    >,
+    #[prost(message, repeated, tag = "5")]
+    pub returning_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "6")]
+    pub with_clause: ::core::option::Option<WithClause>,
+    #[prost(enumeration = "OverridingKind", tag = "7")]
+    pub r#override: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DeleteStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub using_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "4")]
+    pub returning_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "5")]
+    pub with_clause: ::core::option::Option<WithClause>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct UpdateStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub target_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "4")]
+    pub from_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub returning_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "6")]
+    pub with_clause: ::core::option::Option<WithClause>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MergeStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub source_relation: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub join_condition: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "4")]
+    pub merge_when_clauses: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub returning_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "6")]
+    pub with_clause: ::core::option::Option<WithClause>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SelectStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub distinct_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub into_clause: ::core::option::Option<::prost::alloc::boxed::Box<IntoClause>>,
+    #[prost(message, repeated, tag = "3")]
+    pub target_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub from_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "6")]
+    pub group_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "7")]
+    pub group_distinct: bool,
+    #[prost(message, optional, boxed, tag = "8")]
+    pub having_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "9")]
+    pub window_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "10")]
+    pub values_lists: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "11")]
+    pub sort_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "12")]
+    pub limit_offset: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "13")]
+    pub limit_count: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "LimitOption", tag = "14")]
+    pub limit_option: i32,
+    #[prost(message, repeated, tag = "15")]
+    pub locking_clause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "16")]
+    pub with_clause: ::core::option::Option<WithClause>,
+    #[prost(enumeration = "SetOperation", tag = "17")]
+    pub op: i32,
+    #[prost(bool, tag = "18")]
+    pub all: bool,
+    #[prost(message, optional, boxed, tag = "19")]
+    pub larg: ::core::option::Option<::prost::alloc::boxed::Box<SelectStmt>>,
+    #[prost(message, optional, boxed, tag = "20")]
+    pub rarg: ::core::option::Option<::prost::alloc::boxed::Box<SelectStmt>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SetOperationStmt {
+    #[prost(enumeration = "SetOperation", tag = "1")]
+    pub op: i32,
+    #[prost(bool, tag = "2")]
+    pub all: bool,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub larg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub rarg: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "5")]
+    pub col_types: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub col_typmods: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "7")]
+    pub col_collations: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "8")]
+    pub group_clauses: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ReturnStmt {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub returnval: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PlAssignStmt {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub indirection: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "3")]
+    pub nnames: i32,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub val: ::core::option::Option<::prost::alloc::boxed::Box<SelectStmt>>,
+    #[prost(int32, tag = "5")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateSchemaStmt {
+    #[prost(string, tag = "1")]
+    pub schemaname: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub authrole: ::core::option::Option<RoleSpec>,
+    #[prost(message, repeated, tag = "3")]
+    pub schema_elts: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "4")]
+    pub if_not_exists: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterTableStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub cmds: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "ObjectType", tag = "3")]
+    pub objtype: i32,
+    #[prost(bool, tag = "4")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ReplicaIdentityStmt {
+    #[prost(string, tag = "1")]
+    pub identity_type: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub name: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterTableCmd {
+    #[prost(enumeration = "AlterTableType", tag = "1")]
+    pub subtype: i32,
+    #[prost(string, tag = "2")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(int32, tag = "3")]
+    pub num: i32,
+    #[prost(message, optional, tag = "4")]
+    pub newowner: ::core::option::Option<RoleSpec>,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub def: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "DropBehavior", tag = "6")]
+    pub behavior: i32,
+    #[prost(bool, tag = "7")]
+    pub missing_ok: bool,
+    #[prost(bool, tag = "8")]
+    pub recurse: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterCollationStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub collname: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterDomainStmt {
+    #[prost(string, tag = "1")]
+    pub subtype: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub type_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "3")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub def: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "DropBehavior", tag = "5")]
+    pub behavior: i32,
+    #[prost(bool, tag = "6")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct GrantStmt {
+    #[prost(bool, tag = "1")]
+    pub is_grant: bool,
+    #[prost(enumeration = "GrantTargetType", tag = "2")]
+    pub targtype: i32,
+    #[prost(enumeration = "ObjectType", tag = "3")]
+    pub objtype: i32,
+    #[prost(message, repeated, tag = "4")]
+    pub objects: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub privileges: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub grantees: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "7")]
+    pub grant_option: bool,
+    #[prost(message, optional, tag = "8")]
+    pub grantor: ::core::option::Option<RoleSpec>,
+    #[prost(enumeration = "DropBehavior", tag = "9")]
+    pub behavior: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ObjectWithArgs {
+    #[prost(message, repeated, tag = "1")]
+    pub objname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub objargs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub objfuncargs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "4")]
+    pub args_unspecified: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AccessPriv {
+    #[prost(string, tag = "1")]
+    pub priv_name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub cols: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct GrantRoleStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub granted_roles: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub grantee_roles: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "3")]
+    pub is_grant: bool,
+    #[prost(message, repeated, tag = "4")]
+    pub opt: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "5")]
+    pub grantor: ::core::option::Option<RoleSpec>,
+    #[prost(enumeration = "DropBehavior", tag = "6")]
+    pub behavior: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterDefaultPrivilegesStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "2")]
+    pub action: ::core::option::Option<GrantStmt>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CopyStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub query: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "3")]
+    pub attlist: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "4")]
+    pub is_from: bool,
+    #[prost(bool, tag = "5")]
+    pub is_program: bool,
+    #[prost(string, tag = "6")]
+    pub filename: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "7")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "8")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct VariableSetStmt {
+    #[prost(enumeration = "VariableSetKind", tag = "1")]
+    pub kind: i32,
+    #[prost(string, tag = "2")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "4")]
+    pub is_local: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct VariableShowStmt {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub table_elts: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub inh_relations: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "4")]
+    pub partbound: ::core::option::Option<PartitionBoundSpec>,
+    #[prost(message, optional, tag = "5")]
+    pub partspec: ::core::option::Option<PartitionSpec>,
+    #[prost(message, optional, tag = "6")]
+    pub of_typename: ::core::option::Option<TypeName>,
+    #[prost(message, repeated, tag = "7")]
+    pub constraints: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "8")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "OnCommitAction", tag = "9")]
+    pub oncommit: i32,
+    #[prost(string, tag = "10")]
+    pub tablespacename: ::prost::alloc::string::String,
+    #[prost(string, tag = "11")]
+    pub access_method: ::prost::alloc::string::String,
+    #[prost(bool, tag = "12")]
+    pub if_not_exists: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct Constraint {
+    #[prost(enumeration = "ConstrType", tag = "1")]
+    pub contype: i32,
+    #[prost(string, tag = "2")]
+    pub conname: ::prost::alloc::string::String,
+    #[prost(bool, tag = "3")]
+    pub deferrable: bool,
+    #[prost(bool, tag = "4")]
+    pub initdeferred: bool,
+    #[prost(bool, tag = "5")]
+    pub skip_validation: bool,
+    #[prost(bool, tag = "6")]
+    pub initially_valid: bool,
+    #[prost(bool, tag = "7")]
+    pub is_no_inherit: bool,
+    #[prost(message, optional, boxed, tag = "8")]
+    pub raw_expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "9")]
+    pub cooked_expr: ::prost::alloc::string::String,
+    #[prost(string, tag = "10")]
+    pub generated_when: ::prost::alloc::string::String,
+    #[prost(int32, tag = "11")]
+    pub inhcount: i32,
+    #[prost(bool, tag = "12")]
+    pub nulls_not_distinct: bool,
+    #[prost(message, repeated, tag = "13")]
+    pub keys: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "14")]
+    pub including: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "15")]
+    pub exclusions: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "16")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "17")]
+    pub indexname: ::prost::alloc::string::String,
+    #[prost(string, tag = "18")]
+    pub indexspace: ::prost::alloc::string::String,
+    #[prost(bool, tag = "19")]
+    pub reset_default_tblspc: bool,
+    #[prost(string, tag = "20")]
+    pub access_method: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "21")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "22")]
+    pub pktable: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "23")]
+    pub fk_attrs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "24")]
+    pub pk_attrs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "25")]
+    pub fk_matchtype: ::prost::alloc::string::String,
+    #[prost(string, tag = "26")]
+    pub fk_upd_action: ::prost::alloc::string::String,
+    #[prost(string, tag = "27")]
+    pub fk_del_action: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "28")]
+    pub fk_del_set_cols: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "29")]
+    pub old_conpfeqop: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint32, tag = "30")]
+    pub old_pktable_oid: u32,
+    #[prost(int32, tag = "31")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateTableSpaceStmt {
+    #[prost(string, tag = "1")]
+    pub tablespacename: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub owner: ::core::option::Option<RoleSpec>,
+    #[prost(string, tag = "3")]
+    pub location: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "4")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DropTableSpaceStmt {
+    #[prost(string, tag = "1")]
+    pub tablespacename: ::prost::alloc::string::String,
+    #[prost(bool, tag = "2")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterTableSpaceOptionsStmt {
+    #[prost(string, tag = "1")]
+    pub tablespacename: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "3")]
+    pub is_reset: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterTableMoveAllStmt {
+    #[prost(string, tag = "1")]
+    pub orig_tablespacename: ::prost::alloc::string::String,
+    #[prost(enumeration = "ObjectType", tag = "2")]
+    pub objtype: i32,
+    #[prost(message, repeated, tag = "3")]
+    pub roles: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "4")]
+    pub new_tablespacename: ::prost::alloc::string::String,
+    #[prost(bool, tag = "5")]
+    pub nowait: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateExtensionStmt {
+    #[prost(string, tag = "1")]
+    pub extname: ::prost::alloc::string::String,
+    #[prost(bool, tag = "2")]
+    pub if_not_exists: bool,
+    #[prost(message, repeated, tag = "3")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterExtensionStmt {
+    #[prost(string, tag = "1")]
+    pub extname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterExtensionContentsStmt {
+    #[prost(string, tag = "1")]
+    pub extname: ::prost::alloc::string::String,
+    #[prost(int32, tag = "2")]
+    pub action: i32,
+    #[prost(enumeration = "ObjectType", tag = "3")]
+    pub objtype: i32,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub object: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateFdwStmt {
+    #[prost(string, tag = "1")]
+    pub fdwname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub func_options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterFdwStmt {
+    #[prost(string, tag = "1")]
+    pub fdwname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub func_options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateForeignServerStmt {
+    #[prost(string, tag = "1")]
+    pub servername: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub servertype: ::prost::alloc::string::String,
+    #[prost(string, tag = "3")]
+    pub version: ::prost::alloc::string::String,
+    #[prost(string, tag = "4")]
+    pub fdwname: ::prost::alloc::string::String,
+    #[prost(bool, tag = "5")]
+    pub if_not_exists: bool,
+    #[prost(message, repeated, tag = "6")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterForeignServerStmt {
+    #[prost(string, tag = "1")]
+    pub servername: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub version: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "4")]
+    pub has_version: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateForeignTableStmt {
+    #[prost(message, optional, tag = "1")]
+    pub base_stmt: ::core::option::Option<CreateStmt>,
+    #[prost(string, tag = "2")]
+    pub servername: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateUserMappingStmt {
+    #[prost(message, optional, tag = "1")]
+    pub user: ::core::option::Option<RoleSpec>,
+    #[prost(string, tag = "2")]
+    pub servername: ::prost::alloc::string::String,
+    #[prost(bool, tag = "3")]
+    pub if_not_exists: bool,
+    #[prost(message, repeated, tag = "4")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterUserMappingStmt {
+    #[prost(message, optional, tag = "1")]
+    pub user: ::core::option::Option<RoleSpec>,
+    #[prost(string, tag = "2")]
+    pub servername: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DropUserMappingStmt {
+    #[prost(message, optional, tag = "1")]
+    pub user: ::core::option::Option<RoleSpec>,
+    #[prost(string, tag = "2")]
+    pub servername: ::prost::alloc::string::String,
+    #[prost(bool, tag = "3")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ImportForeignSchemaStmt {
+    #[prost(string, tag = "1")]
+    pub server_name: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub remote_schema: ::prost::alloc::string::String,
+    #[prost(string, tag = "3")]
+    pub local_schema: ::prost::alloc::string::String,
+    #[prost(enumeration = "ImportForeignSchemaType", tag = "4")]
+    pub list_type: i32,
+    #[prost(message, repeated, tag = "5")]
+    pub table_list: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreatePolicyStmt {
+    #[prost(string, tag = "1")]
+    pub policy_name: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub table: ::core::option::Option<RangeVar>,
+    #[prost(string, tag = "3")]
+    pub cmd_name: ::prost::alloc::string::String,
+    #[prost(bool, tag = "4")]
+    pub permissive: bool,
+    #[prost(message, repeated, tag = "5")]
+    pub roles: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "6")]
+    pub qual: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "7")]
+    pub with_check: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterPolicyStmt {
+    #[prost(string, tag = "1")]
+    pub policy_name: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub table: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "3")]
+    pub roles: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub qual: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "5")]
+    pub with_check: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateAmStmt {
+    #[prost(string, tag = "1")]
+    pub amname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub handler_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "3")]
+    pub amtype: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateTrigStmt {
+    #[prost(bool, tag = "1")]
+    pub replace: bool,
+    #[prost(bool, tag = "2")]
+    pub isconstraint: bool,
+    #[prost(string, tag = "3")]
+    pub trigname: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "4")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "5")]
+    pub funcname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "7")]
+    pub row: bool,
+    #[prost(int32, tag = "8")]
+    pub timing: i32,
+    #[prost(int32, tag = "9")]
+    pub events: i32,
+    #[prost(message, repeated, tag = "10")]
+    pub columns: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "11")]
+    pub when_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "12")]
+    pub transition_rels: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "13")]
+    pub deferrable: bool,
+    #[prost(bool, tag = "14")]
+    pub initdeferred: bool,
+    #[prost(message, optional, tag = "15")]
+    pub constrrel: ::core::option::Option<RangeVar>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateEventTrigStmt {
+    #[prost(string, tag = "1")]
+    pub trigname: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub eventname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub whenclause: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub funcname: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterEventTrigStmt {
+    #[prost(string, tag = "1")]
+    pub trigname: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub tgenabled: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreatePLangStmt {
+    #[prost(bool, tag = "1")]
+    pub replace: bool,
+    #[prost(string, tag = "2")]
+    pub plname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub plhandler: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub plinline: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub plvalidator: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "6")]
+    pub pltrusted: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateRoleStmt {
+    #[prost(enumeration = "RoleStmtType", tag = "1")]
+    pub stmt_type: i32,
+    #[prost(string, tag = "2")]
+    pub role: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterRoleStmt {
+    #[prost(message, optional, tag = "1")]
+    pub role: ::core::option::Option<RoleSpec>,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "3")]
+    pub action: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterRoleSetStmt {
+    #[prost(message, optional, tag = "1")]
+    pub role: ::core::option::Option<RoleSpec>,
+    #[prost(string, tag = "2")]
+    pub database: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "3")]
+    pub setstmt: ::core::option::Option<VariableSetStmt>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DropRoleStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub roles: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "2")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateSeqStmt {
+    #[prost(message, optional, tag = "1")]
+    pub sequence: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(uint32, tag = "3")]
+    pub owner_id: u32,
+    #[prost(bool, tag = "4")]
+    pub for_identity: bool,
+    #[prost(bool, tag = "5")]
+    pub if_not_exists: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterSeqStmt {
+    #[prost(message, optional, tag = "1")]
+    pub sequence: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "3")]
+    pub for_identity: bool,
+    #[prost(bool, tag = "4")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DefineStmt {
+    #[prost(enumeration = "ObjectType", tag = "1")]
+    pub kind: i32,
+    #[prost(bool, tag = "2")]
+    pub oldstyle: bool,
+    #[prost(message, repeated, tag = "3")]
+    pub defnames: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub definition: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "6")]
+    pub if_not_exists: bool,
+    #[prost(bool, tag = "7")]
+    pub replace: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateDomainStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub domainname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "2")]
+    pub type_name: ::core::option::Option<TypeName>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub coll_clause: ::core::option::Option<::prost::alloc::boxed::Box<CollateClause>>,
+    #[prost(message, repeated, tag = "4")]
+    pub constraints: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateOpClassStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub opclassname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub opfamilyname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "3")]
+    pub amname: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "4")]
+    pub datatype: ::core::option::Option<TypeName>,
+    #[prost(message, repeated, tag = "5")]
+    pub items: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "6")]
+    pub is_default: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateOpClassItem {
+    #[prost(int32, tag = "1")]
+    pub itemtype: i32,
+    #[prost(message, optional, tag = "2")]
+    pub name: ::core::option::Option<ObjectWithArgs>,
+    #[prost(int32, tag = "3")]
+    pub number: i32,
+    #[prost(message, repeated, tag = "4")]
+    pub order_family: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub class_args: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "6")]
+    pub storedtype: ::core::option::Option<TypeName>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateOpFamilyStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub opfamilyname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "2")]
+    pub amname: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterOpFamilyStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub opfamilyname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "2")]
+    pub amname: ::prost::alloc::string::String,
+    #[prost(bool, tag = "3")]
+    pub is_drop: bool,
+    #[prost(message, repeated, tag = "4")]
+    pub items: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DropStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub objects: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "ObjectType", tag = "2")]
+    pub remove_type: i32,
+    #[prost(enumeration = "DropBehavior", tag = "3")]
+    pub behavior: i32,
+    #[prost(bool, tag = "4")]
+    pub missing_ok: bool,
+    #[prost(bool, tag = "5")]
+    pub concurrent: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TruncateStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub relations: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "2")]
+    pub restart_seqs: bool,
+    #[prost(enumeration = "DropBehavior", tag = "3")]
+    pub behavior: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CommentStmt {
+    #[prost(enumeration = "ObjectType", tag = "1")]
+    pub objtype: i32,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub object: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "3")]
+    pub comment: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct SecLabelStmt {
+    #[prost(enumeration = "ObjectType", tag = "1")]
+    pub objtype: i32,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub object: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "3")]
+    pub provider: ::prost::alloc::string::String,
+    #[prost(string, tag = "4")]
+    pub label: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DeclareCursorStmt {
+    #[prost(string, tag = "1")]
+    pub portalname: ::prost::alloc::string::String,
+    #[prost(int32, tag = "2")]
+    pub options: i32,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub query: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ClosePortalStmt {
+    #[prost(string, tag = "1")]
+    pub portalname: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct FetchStmt {
+    #[prost(enumeration = "FetchDirection", tag = "1")]
+    pub direction: i32,
+    #[prost(int64, tag = "2")]
+    pub how_many: i64,
+    #[prost(string, tag = "3")]
+    pub portalname: ::prost::alloc::string::String,
+    #[prost(bool, tag = "4")]
+    pub ismove: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct IndexStmt {
+    #[prost(string, tag = "1")]
+    pub idxname: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(string, tag = "3")]
+    pub access_method: ::prost::alloc::string::String,
+    #[prost(string, tag = "4")]
+    pub table_space: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "5")]
+    pub index_params: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "6")]
+    pub index_including_params: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "7")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "8")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "9")]
+    pub exclude_op_names: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "10")]
+    pub idxcomment: ::prost::alloc::string::String,
+    #[prost(uint32, tag = "11")]
+    pub index_oid: u32,
+    #[prost(uint32, tag = "12")]
+    pub old_number: u32,
+    #[prost(uint32, tag = "13")]
+    pub old_create_subid: u32,
+    #[prost(uint32, tag = "14")]
+    pub old_first_relfilelocator_subid: u32,
+    #[prost(bool, tag = "15")]
+    pub unique: bool,
+    #[prost(bool, tag = "16")]
+    pub nulls_not_distinct: bool,
+    #[prost(bool, tag = "17")]
+    pub primary: bool,
+    #[prost(bool, tag = "18")]
+    pub isconstraint: bool,
+    #[prost(bool, tag = "19")]
+    pub deferrable: bool,
+    #[prost(bool, tag = "20")]
+    pub initdeferred: bool,
+    #[prost(bool, tag = "21")]
+    pub transformed: bool,
+    #[prost(bool, tag = "22")]
+    pub concurrent: bool,
+    #[prost(bool, tag = "23")]
+    pub if_not_exists: bool,
+    #[prost(bool, tag = "24")]
+    pub reset_default_tblspc: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateStatsStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub defnames: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub stat_types: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub exprs: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub relations: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "5")]
+    pub stxcomment: ::prost::alloc::string::String,
+    #[prost(bool, tag = "6")]
+    pub transformed: bool,
+    #[prost(bool, tag = "7")]
+    pub if_not_exists: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct StatsElem {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub expr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterStatsStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub defnames: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub stxstattarget: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(bool, tag = "3")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateFunctionStmt {
+    #[prost(bool, tag = "1")]
+    pub is_procedure: bool,
+    #[prost(bool, tag = "2")]
+    pub replace: bool,
+    #[prost(message, repeated, tag = "3")]
+    pub funcname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub parameters: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "5")]
+    pub return_type: ::core::option::Option<TypeName>,
+    #[prost(message, repeated, tag = "6")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "7")]
+    pub sql_body: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct FunctionParameter {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub arg_type: ::core::option::Option<TypeName>,
+    #[prost(enumeration = "FunctionParameterMode", tag = "3")]
+    pub mode: i32,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub defexpr: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterFunctionStmt {
+    #[prost(enumeration = "ObjectType", tag = "1")]
+    pub objtype: i32,
+    #[prost(message, optional, tag = "2")]
+    pub func: ::core::option::Option<ObjectWithArgs>,
+    #[prost(message, repeated, tag = "3")]
+    pub actions: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DoStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub args: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct InlineCodeBlock {
+    #[prost(string, tag = "1")]
+    pub source_text: ::prost::alloc::string::String,
+    #[prost(uint32, tag = "2")]
+    pub lang_oid: u32,
+    #[prost(bool, tag = "3")]
+    pub lang_is_trusted: bool,
+    #[prost(bool, tag = "4")]
+    pub atomic: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CallStmt {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub funccall: ::core::option::Option<::prost::alloc::boxed::Box<FuncCall>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub funcexpr: ::core::option::Option<::prost::alloc::boxed::Box<FuncExpr>>,
+    #[prost(message, repeated, tag = "3")]
+    pub outargs: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct CallContext {
+    #[prost(bool, tag = "1")]
+    pub atomic: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RenameStmt {
+    #[prost(enumeration = "ObjectType", tag = "1")]
+    pub rename_type: i32,
+    #[prost(enumeration = "ObjectType", tag = "2")]
+    pub relation_type: i32,
+    #[prost(message, optional, tag = "3")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, optional, boxed, tag = "4")]
+    pub object: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "5")]
+    pub subname: ::prost::alloc::string::String,
+    #[prost(string, tag = "6")]
+    pub newname: ::prost::alloc::string::String,
+    #[prost(enumeration = "DropBehavior", tag = "7")]
+    pub behavior: i32,
+    #[prost(bool, tag = "8")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterObjectDependsStmt {
+    #[prost(enumeration = "ObjectType", tag = "1")]
+    pub object_type: i32,
+    #[prost(message, optional, tag = "2")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub object: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "4")]
+    pub extname: ::core::option::Option<String>,
+    #[prost(bool, tag = "5")]
+    pub remove: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterObjectSchemaStmt {
+    #[prost(enumeration = "ObjectType", tag = "1")]
+    pub object_type: i32,
+    #[prost(message, optional, tag = "2")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub object: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(string, tag = "4")]
+    pub newschema: ::prost::alloc::string::String,
+    #[prost(bool, tag = "5")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterOwnerStmt {
+    #[prost(enumeration = "ObjectType", tag = "1")]
+    pub object_type: i32,
+    #[prost(message, optional, tag = "2")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub object: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, tag = "4")]
+    pub newowner: ::core::option::Option<RoleSpec>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterOperatorStmt {
+    #[prost(message, optional, tag = "1")]
+    pub opername: ::core::option::Option<ObjectWithArgs>,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterTypeStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub type_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RuleStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(string, tag = "2")]
+    pub rulename: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(enumeration = "CmdType", tag = "4")]
+    pub event: i32,
+    #[prost(bool, tag = "5")]
+    pub instead: bool,
+    #[prost(message, repeated, tag = "6")]
+    pub actions: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "7")]
+    pub replace: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct NotifyStmt {
+    #[prost(string, tag = "1")]
+    pub conditionname: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub payload: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ListenStmt {
+    #[prost(string, tag = "1")]
+    pub conditionname: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct UnlistenStmt {
+    #[prost(string, tag = "1")]
+    pub conditionname: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TransactionStmt {
+    #[prost(enumeration = "TransactionStmtKind", tag = "1")]
+    pub kind: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "3")]
+    pub savepoint_name: ::prost::alloc::string::String,
+    #[prost(string, tag = "4")]
+    pub gid: ::prost::alloc::string::String,
+    #[prost(bool, tag = "5")]
+    pub chain: bool,
+    #[prost(int32, tag = "6")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CompositeTypeStmt {
+    #[prost(message, optional, tag = "1")]
+    pub typevar: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub coldeflist: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateEnumStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub type_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub vals: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateRangeStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub type_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub params: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterEnumStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub type_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "2")]
+    pub old_val: ::prost::alloc::string::String,
+    #[prost(string, tag = "3")]
+    pub new_val: ::prost::alloc::string::String,
+    #[prost(string, tag = "4")]
+    pub new_val_neighbor: ::prost::alloc::string::String,
+    #[prost(bool, tag = "5")]
+    pub new_val_is_after: bool,
+    #[prost(bool, tag = "6")]
+    pub skip_if_new_val_exists: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ViewStmt {
+    #[prost(message, optional, tag = "1")]
+    pub view: ::core::option::Option<RangeVar>,
+    #[prost(message, repeated, tag = "2")]
+    pub aliases: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub query: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(bool, tag = "4")]
+    pub replace: bool,
+    #[prost(message, repeated, tag = "5")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "ViewCheckOption", tag = "6")]
+    pub with_check_option: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct LoadStmt {
+    #[prost(string, tag = "1")]
+    pub filename: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreatedbStmt {
+    #[prost(string, tag = "1")]
+    pub dbname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterDatabaseStmt {
+    #[prost(string, tag = "1")]
+    pub dbname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterDatabaseRefreshCollStmt {
+    #[prost(string, tag = "1")]
+    pub dbname: ::prost::alloc::string::String,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterDatabaseSetStmt {
+    #[prost(string, tag = "1")]
+    pub dbname: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "2")]
+    pub setstmt: ::core::option::Option<VariableSetStmt>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DropdbStmt {
+    #[prost(string, tag = "1")]
+    pub dbname: ::prost::alloc::string::String,
+    #[prost(bool, tag = "2")]
+    pub missing_ok: bool,
+    #[prost(message, repeated, tag = "3")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterSystemStmt {
+    #[prost(message, optional, tag = "1")]
+    pub setstmt: ::core::option::Option<VariableSetStmt>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ClusterStmt {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(string, tag = "2")]
+    pub indexname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub params: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct VacuumStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub rels: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "3")]
+    pub is_vacuumcmd: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct VacuumRelation {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(uint32, tag = "2")]
+    pub oid: u32,
+    #[prost(message, repeated, tag = "3")]
+    pub va_cols: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ExplainStmt {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub query: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateTableAsStmt {
+    #[prost(message, optional, boxed, tag = "1")]
+    pub query: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub into: ::core::option::Option<::prost::alloc::boxed::Box<IntoClause>>,
+    #[prost(enumeration = "ObjectType", tag = "3")]
+    pub objtype: i32,
+    #[prost(bool, tag = "4")]
+    pub is_select_into: bool,
+    #[prost(bool, tag = "5")]
+    pub if_not_exists: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RefreshMatViewStmt {
+    #[prost(bool, tag = "1")]
+    pub concurrent: bool,
+    #[prost(bool, tag = "2")]
+    pub skip_data: bool,
+    #[prost(message, optional, tag = "3")]
+    pub relation: ::core::option::Option<RangeVar>,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct CheckPointStmt {}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct DiscardStmt {
+    #[prost(enumeration = "DiscardMode", tag = "1")]
+    pub target: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct LockStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub relations: ::prost::alloc::vec::Vec<Node>,
+    #[prost(int32, tag = "2")]
+    pub mode: i32,
+    #[prost(bool, tag = "3")]
+    pub nowait: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ConstraintsSetStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub constraints: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "2")]
+    pub deferred: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ReindexStmt {
+    #[prost(enumeration = "ReindexObjectType", tag = "1")]
+    pub kind: i32,
+    #[prost(message, optional, tag = "2")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(string, tag = "3")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "4")]
+    pub params: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateConversionStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub conversion_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(string, tag = "2")]
+    pub for_encoding_name: ::prost::alloc::string::String,
+    #[prost(string, tag = "3")]
+    pub to_encoding_name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "4")]
+    pub func_name: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "5")]
+    pub def: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateCastStmt {
+    #[prost(message, optional, tag = "1")]
+    pub sourcetype: ::core::option::Option<TypeName>,
+    #[prost(message, optional, tag = "2")]
+    pub targettype: ::core::option::Option<TypeName>,
+    #[prost(message, optional, tag = "3")]
+    pub func: ::core::option::Option<ObjectWithArgs>,
+    #[prost(enumeration = "CoercionContext", tag = "4")]
+    pub context: i32,
+    #[prost(bool, tag = "5")]
+    pub inout: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateTransformStmt {
+    #[prost(bool, tag = "1")]
+    pub replace: bool,
+    #[prost(message, optional, tag = "2")]
+    pub type_name: ::core::option::Option<TypeName>,
+    #[prost(string, tag = "3")]
+    pub lang: ::prost::alloc::string::String,
+    #[prost(message, optional, tag = "4")]
+    pub fromsql: ::core::option::Option<ObjectWithArgs>,
+    #[prost(message, optional, tag = "5")]
+    pub tosql: ::core::option::Option<ObjectWithArgs>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PrepareStmt {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub argtypes: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub query: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ExecuteStmt {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub params: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DeallocateStmt {
+    #[prost(string, tag = "1")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(bool, tag = "2")]
+    pub isall: bool,
+    #[prost(int32, tag = "3")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DropOwnedStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub roles: ::prost::alloc::vec::Vec<Node>,
+    #[prost(enumeration = "DropBehavior", tag = "2")]
+    pub behavior: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ReassignOwnedStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub roles: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, optional, tag = "2")]
+    pub newrole: ::core::option::Option<RoleSpec>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterTsDictionaryStmt {
+    #[prost(message, repeated, tag = "1")]
+    pub dictname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterTsConfigurationStmt {
+    #[prost(enumeration = "AlterTsConfigType", tag = "1")]
+    pub kind: i32,
+    #[prost(message, repeated, tag = "2")]
+    pub cfgname: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub tokentype: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub dicts: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "5")]
+    pub r#override: bool,
+    #[prost(bool, tag = "6")]
+    pub replace: bool,
+    #[prost(bool, tag = "7")]
+    pub missing_ok: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PublicationTable {
+    #[prost(message, optional, tag = "1")]
+    pub relation: ::core::option::Option<RangeVar>,
+    #[prost(message, optional, boxed, tag = "2")]
+    pub where_clause: ::core::option::Option<::prost::alloc::boxed::Box<Node>>,
+    #[prost(message, repeated, tag = "3")]
+    pub columns: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PublicationObjSpec {
+    #[prost(enumeration = "PublicationObjSpecType", tag = "1")]
+    pub pubobjtype: i32,
+    #[prost(string, tag = "2")]
+    pub name: ::prost::alloc::string::String,
+    #[prost(message, optional, boxed, tag = "3")]
+    pub pubtable: ::core::option::Option<::prost::alloc::boxed::Box<PublicationTable>>,
+    #[prost(int32, tag = "4")]
+    pub location: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreatePublicationStmt {
+    #[prost(string, tag = "1")]
+    pub pubname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub pubobjects: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "4")]
+    pub for_all_tables: bool,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterPublicationStmt {
+    #[prost(string, tag = "1")]
+    pub pubname: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "2")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "3")]
+    pub pubobjects: ::prost::alloc::vec::Vec<Node>,
+    #[prost(bool, tag = "4")]
+    pub for_all_tables: bool,
+    #[prost(enumeration = "AlterPublicationAction", tag = "5")]
+    pub action: i32,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CreateSubscriptionStmt {
+    #[prost(string, tag = "1")]
+    pub subname: ::prost::alloc::string::String,
+    #[prost(string, tag = "2")]
+    pub conninfo: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "3")]
+    pub publication: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "4")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct AlterSubscriptionStmt {
+    #[prost(enumeration = "AlterSubscriptionType", tag = "1")]
+    pub kind: i32,
+    #[prost(string, tag = "2")]
+    pub subname: ::prost::alloc::string::String,
+    #[prost(string, tag = "3")]
+    pub conninfo: ::prost::alloc::string::String,
+    #[prost(message, repeated, tag = "4")]
+    pub publication: ::prost::alloc::vec::Vec<Node>,
+    #[prost(message, repeated, tag = "5")]
+    pub options: ::prost::alloc::vec::Vec<Node>,
+}
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct DropSubscriptionStmt {
+    #[prost(string, tag = "1")]
+    pub subname: ::prost::alloc::string::String,
+    #[prost(bool, tag = "2")]
+    pub missing_ok: bool,
+    #[prost(enumeration = "DropBehavior", tag = "3")]
+    pub behavior: i32,
+}
+#[derive(Clone, Copy, PartialEq, ::prost::Message)]
+pub struct ScanToken {
+    #[prost(int32, tag = "1")]
+    pub start: i32,
+    #[prost(int32, tag = "2")]
+    pub end: i32,
+    #[prost(enumeration = "Token", tag = "4")]
+    pub token: i32,
+    #[prost(enumeration = "KeywordKind", tag = "5")]
+    pub keyword_kind: i32,
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum QuerySource {
+    Undefined = 0,
+    QsrcOriginal = 1,
+    QsrcParser = 2,
+    QsrcInsteadRule = 3,
+    QsrcQualInsteadRule = 4,
+    QsrcNonInsteadRule = 5,
+}
+impl QuerySource {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "QUERY_SOURCE_UNDEFINED",
+            Self::QsrcOriginal => "QSRC_ORIGINAL",
+            Self::QsrcParser => "QSRC_PARSER",
+            Self::QsrcInsteadRule => "QSRC_INSTEAD_RULE",
+            Self::QsrcQualInsteadRule => "QSRC_QUAL_INSTEAD_RULE",
+            Self::QsrcNonInsteadRule => "QSRC_NON_INSTEAD_RULE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "QUERY_SOURCE_UNDEFINED" => Some(Self::Undefined),
+            "QSRC_ORIGINAL" => Some(Self::QsrcOriginal),
+            "QSRC_PARSER" => Some(Self::QsrcParser),
+            "QSRC_INSTEAD_RULE" => Some(Self::QsrcInsteadRule),
+            "QSRC_QUAL_INSTEAD_RULE" => Some(Self::QsrcQualInsteadRule),
+            "QSRC_NON_INSTEAD_RULE" => Some(Self::QsrcNonInsteadRule),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum SortByDir {
+    Undefined = 0,
+    SortbyDefault = 1,
+    SortbyAsc = 2,
+    SortbyDesc = 3,
+    SortbyUsing = 4,
+}
+impl SortByDir {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "SORT_BY_DIR_UNDEFINED",
+            Self::SortbyDefault => "SORTBY_DEFAULT",
+            Self::SortbyAsc => "SORTBY_ASC",
+            Self::SortbyDesc => "SORTBY_DESC",
+            Self::SortbyUsing => "SORTBY_USING",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "SORT_BY_DIR_UNDEFINED" => Some(Self::Undefined),
+            "SORTBY_DEFAULT" => Some(Self::SortbyDefault),
+            "SORTBY_ASC" => Some(Self::SortbyAsc),
+            "SORTBY_DESC" => Some(Self::SortbyDesc),
+            "SORTBY_USING" => Some(Self::SortbyUsing),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum SortByNulls {
+    Undefined = 0,
+    SortbyNullsDefault = 1,
+    SortbyNullsFirst = 2,
+    SortbyNullsLast = 3,
+}
+impl SortByNulls {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "SORT_BY_NULLS_UNDEFINED",
+            Self::SortbyNullsDefault => "SORTBY_NULLS_DEFAULT",
+            Self::SortbyNullsFirst => "SORTBY_NULLS_FIRST",
+            Self::SortbyNullsLast => "SORTBY_NULLS_LAST",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "SORT_BY_NULLS_UNDEFINED" => Some(Self::Undefined),
+            "SORTBY_NULLS_DEFAULT" => Some(Self::SortbyNullsDefault),
+            "SORTBY_NULLS_FIRST" => Some(Self::SortbyNullsFirst),
+            "SORTBY_NULLS_LAST" => Some(Self::SortbyNullsLast),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum SetQuantifier {
+    Undefined = 0,
+    Default = 1,
+    All = 2,
+    Distinct = 3,
+}
+impl SetQuantifier {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "SET_QUANTIFIER_UNDEFINED",
+            Self::Default => "SET_QUANTIFIER_DEFAULT",
+            Self::All => "SET_QUANTIFIER_ALL",
+            Self::Distinct => "SET_QUANTIFIER_DISTINCT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "SET_QUANTIFIER_UNDEFINED" => Some(Self::Undefined),
+            "SET_QUANTIFIER_DEFAULT" => Some(Self::Default),
+            "SET_QUANTIFIER_ALL" => Some(Self::All),
+            "SET_QUANTIFIER_DISTINCT" => Some(Self::Distinct),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum AExprKind {
+    Undefined = 0,
+    AexprOp = 1,
+    AexprOpAny = 2,
+    AexprOpAll = 3,
+    AexprDistinct = 4,
+    AexprNotDistinct = 5,
+    AexprNullif = 6,
+    AexprIn = 7,
+    AexprLike = 8,
+    AexprIlike = 9,
+    AexprSimilar = 10,
+    AexprBetween = 11,
+    AexprNotBetween = 12,
+    AexprBetweenSym = 13,
+    AexprNotBetweenSym = 14,
+}
+impl AExprKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "A_EXPR_KIND_UNDEFINED",
+            Self::AexprOp => "AEXPR_OP",
+            Self::AexprOpAny => "AEXPR_OP_ANY",
+            Self::AexprOpAll => "AEXPR_OP_ALL",
+            Self::AexprDistinct => "AEXPR_DISTINCT",
+            Self::AexprNotDistinct => "AEXPR_NOT_DISTINCT",
+            Self::AexprNullif => "AEXPR_NULLIF",
+            Self::AexprIn => "AEXPR_IN",
+            Self::AexprLike => "AEXPR_LIKE",
+            Self::AexprIlike => "AEXPR_ILIKE",
+            Self::AexprSimilar => "AEXPR_SIMILAR",
+            Self::AexprBetween => "AEXPR_BETWEEN",
+            Self::AexprNotBetween => "AEXPR_NOT_BETWEEN",
+            Self::AexprBetweenSym => "AEXPR_BETWEEN_SYM",
+            Self::AexprNotBetweenSym => "AEXPR_NOT_BETWEEN_SYM",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "A_EXPR_KIND_UNDEFINED" => Some(Self::Undefined),
+            "AEXPR_OP" => Some(Self::AexprOp),
+            "AEXPR_OP_ANY" => Some(Self::AexprOpAny),
+            "AEXPR_OP_ALL" => Some(Self::AexprOpAll),
+            "AEXPR_DISTINCT" => Some(Self::AexprDistinct),
+            "AEXPR_NOT_DISTINCT" => Some(Self::AexprNotDistinct),
+            "AEXPR_NULLIF" => Some(Self::AexprNullif),
+            "AEXPR_IN" => Some(Self::AexprIn),
+            "AEXPR_LIKE" => Some(Self::AexprLike),
+            "AEXPR_ILIKE" => Some(Self::AexprIlike),
+            "AEXPR_SIMILAR" => Some(Self::AexprSimilar),
+            "AEXPR_BETWEEN" => Some(Self::AexprBetween),
+            "AEXPR_NOT_BETWEEN" => Some(Self::AexprNotBetween),
+            "AEXPR_BETWEEN_SYM" => Some(Self::AexprBetweenSym),
+            "AEXPR_NOT_BETWEEN_SYM" => Some(Self::AexprNotBetweenSym),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum RoleSpecType {
+    Undefined = 0,
+    RolespecCstring = 1,
+    RolespecCurrentRole = 2,
+    RolespecCurrentUser = 3,
+    RolespecSessionUser = 4,
+    RolespecPublic = 5,
+}
+impl RoleSpecType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "ROLE_SPEC_TYPE_UNDEFINED",
+            Self::RolespecCstring => "ROLESPEC_CSTRING",
+            Self::RolespecCurrentRole => "ROLESPEC_CURRENT_ROLE",
+            Self::RolespecCurrentUser => "ROLESPEC_CURRENT_USER",
+            Self::RolespecSessionUser => "ROLESPEC_SESSION_USER",
+            Self::RolespecPublic => "ROLESPEC_PUBLIC",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ROLE_SPEC_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "ROLESPEC_CSTRING" => Some(Self::RolespecCstring),
+            "ROLESPEC_CURRENT_ROLE" => Some(Self::RolespecCurrentRole),
+            "ROLESPEC_CURRENT_USER" => Some(Self::RolespecCurrentUser),
+            "ROLESPEC_SESSION_USER" => Some(Self::RolespecSessionUser),
+            "ROLESPEC_PUBLIC" => Some(Self::RolespecPublic),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum TableLikeOption {
+    Undefined = 0,
+    CreateTableLikeComments = 1,
+    CreateTableLikeCompression = 2,
+    CreateTableLikeConstraints = 3,
+    CreateTableLikeDefaults = 4,
+    CreateTableLikeGenerated = 5,
+    CreateTableLikeIdentity = 6,
+    CreateTableLikeIndexes = 7,
+    CreateTableLikeStatistics = 8,
+    CreateTableLikeStorage = 9,
+    CreateTableLikeAll = 10,
+}
+impl TableLikeOption {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "TABLE_LIKE_OPTION_UNDEFINED",
+            Self::CreateTableLikeComments => "CREATE_TABLE_LIKE_COMMENTS",
+            Self::CreateTableLikeCompression => "CREATE_TABLE_LIKE_COMPRESSION",
+            Self::CreateTableLikeConstraints => "CREATE_TABLE_LIKE_CONSTRAINTS",
+            Self::CreateTableLikeDefaults => "CREATE_TABLE_LIKE_DEFAULTS",
+            Self::CreateTableLikeGenerated => "CREATE_TABLE_LIKE_GENERATED",
+            Self::CreateTableLikeIdentity => "CREATE_TABLE_LIKE_IDENTITY",
+            Self::CreateTableLikeIndexes => "CREATE_TABLE_LIKE_INDEXES",
+            Self::CreateTableLikeStatistics => "CREATE_TABLE_LIKE_STATISTICS",
+            Self::CreateTableLikeStorage => "CREATE_TABLE_LIKE_STORAGE",
+            Self::CreateTableLikeAll => "CREATE_TABLE_LIKE_ALL",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "TABLE_LIKE_OPTION_UNDEFINED" => Some(Self::Undefined),
+            "CREATE_TABLE_LIKE_COMMENTS" => Some(Self::CreateTableLikeComments),
+            "CREATE_TABLE_LIKE_COMPRESSION" => Some(Self::CreateTableLikeCompression),
+            "CREATE_TABLE_LIKE_CONSTRAINTS" => Some(Self::CreateTableLikeConstraints),
+            "CREATE_TABLE_LIKE_DEFAULTS" => Some(Self::CreateTableLikeDefaults),
+            "CREATE_TABLE_LIKE_GENERATED" => Some(Self::CreateTableLikeGenerated),
+            "CREATE_TABLE_LIKE_IDENTITY" => Some(Self::CreateTableLikeIdentity),
+            "CREATE_TABLE_LIKE_INDEXES" => Some(Self::CreateTableLikeIndexes),
+            "CREATE_TABLE_LIKE_STATISTICS" => Some(Self::CreateTableLikeStatistics),
+            "CREATE_TABLE_LIKE_STORAGE" => Some(Self::CreateTableLikeStorage),
+            "CREATE_TABLE_LIKE_ALL" => Some(Self::CreateTableLikeAll),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum DefElemAction {
+    Undefined = 0,
+    DefelemUnspec = 1,
+    DefelemSet = 2,
+    DefelemAdd = 3,
+    DefelemDrop = 4,
+}
+impl DefElemAction {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "DEF_ELEM_ACTION_UNDEFINED",
+            Self::DefelemUnspec => "DEFELEM_UNSPEC",
+            Self::DefelemSet => "DEFELEM_SET",
+            Self::DefelemAdd => "DEFELEM_ADD",
+            Self::DefelemDrop => "DEFELEM_DROP",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "DEF_ELEM_ACTION_UNDEFINED" => Some(Self::Undefined),
+            "DEFELEM_UNSPEC" => Some(Self::DefelemUnspec),
+            "DEFELEM_SET" => Some(Self::DefelemSet),
+            "DEFELEM_ADD" => Some(Self::DefelemAdd),
+            "DEFELEM_DROP" => Some(Self::DefelemDrop),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum PartitionStrategy {
+    Undefined = 0,
+    List = 1,
+    Range = 2,
+    Hash = 3,
+}
+impl PartitionStrategy {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "PARTITION_STRATEGY_UNDEFINED",
+            Self::List => "PARTITION_STRATEGY_LIST",
+            Self::Range => "PARTITION_STRATEGY_RANGE",
+            Self::Hash => "PARTITION_STRATEGY_HASH",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "PARTITION_STRATEGY_UNDEFINED" => Some(Self::Undefined),
+            "PARTITION_STRATEGY_LIST" => Some(Self::List),
+            "PARTITION_STRATEGY_RANGE" => Some(Self::Range),
+            "PARTITION_STRATEGY_HASH" => Some(Self::Hash),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum PartitionRangeDatumKind {
+    Undefined = 0,
+    PartitionRangeDatumMinvalue = 1,
+    PartitionRangeDatumValue = 2,
+    PartitionRangeDatumMaxvalue = 3,
+}
+impl PartitionRangeDatumKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "PARTITION_RANGE_DATUM_KIND_UNDEFINED",
+            Self::PartitionRangeDatumMinvalue => "PARTITION_RANGE_DATUM_MINVALUE",
+            Self::PartitionRangeDatumValue => "PARTITION_RANGE_DATUM_VALUE",
+            Self::PartitionRangeDatumMaxvalue => "PARTITION_RANGE_DATUM_MAXVALUE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "PARTITION_RANGE_DATUM_KIND_UNDEFINED" => Some(Self::Undefined),
+            "PARTITION_RANGE_DATUM_MINVALUE" => Some(Self::PartitionRangeDatumMinvalue),
+            "PARTITION_RANGE_DATUM_VALUE" => Some(Self::PartitionRangeDatumValue),
+            "PARTITION_RANGE_DATUM_MAXVALUE" => Some(Self::PartitionRangeDatumMaxvalue),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum RteKind {
+    RtekindUndefined = 0,
+    RteRelation = 1,
+    RteSubquery = 2,
+    RteJoin = 3,
+    RteFunction = 4,
+    RteTablefunc = 5,
+    RteValues = 6,
+    RteCte = 7,
+    RteNamedtuplestore = 8,
+    RteResult = 9,
+}
+impl RteKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::RtekindUndefined => "RTEKIND_UNDEFINED",
+            Self::RteRelation => "RTE_RELATION",
+            Self::RteSubquery => "RTE_SUBQUERY",
+            Self::RteJoin => "RTE_JOIN",
+            Self::RteFunction => "RTE_FUNCTION",
+            Self::RteTablefunc => "RTE_TABLEFUNC",
+            Self::RteValues => "RTE_VALUES",
+            Self::RteCte => "RTE_CTE",
+            Self::RteNamedtuplestore => "RTE_NAMEDTUPLESTORE",
+            Self::RteResult => "RTE_RESULT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "RTEKIND_UNDEFINED" => Some(Self::RtekindUndefined),
+            "RTE_RELATION" => Some(Self::RteRelation),
+            "RTE_SUBQUERY" => Some(Self::RteSubquery),
+            "RTE_JOIN" => Some(Self::RteJoin),
+            "RTE_FUNCTION" => Some(Self::RteFunction),
+            "RTE_TABLEFUNC" => Some(Self::RteTablefunc),
+            "RTE_VALUES" => Some(Self::RteValues),
+            "RTE_CTE" => Some(Self::RteCte),
+            "RTE_NAMEDTUPLESTORE" => Some(Self::RteNamedtuplestore),
+            "RTE_RESULT" => Some(Self::RteResult),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum WcoKind {
+    WcokindUndefined = 0,
+    WcoViewCheck = 1,
+    WcoRlsInsertCheck = 2,
+    WcoRlsUpdateCheck = 3,
+    WcoRlsConflictCheck = 4,
+    WcoRlsMergeUpdateCheck = 5,
+    WcoRlsMergeDeleteCheck = 6,
+}
+impl WcoKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::WcokindUndefined => "WCOKIND_UNDEFINED",
+            Self::WcoViewCheck => "WCO_VIEW_CHECK",
+            Self::WcoRlsInsertCheck => "WCO_RLS_INSERT_CHECK",
+            Self::WcoRlsUpdateCheck => "WCO_RLS_UPDATE_CHECK",
+            Self::WcoRlsConflictCheck => "WCO_RLS_CONFLICT_CHECK",
+            Self::WcoRlsMergeUpdateCheck => "WCO_RLS_MERGE_UPDATE_CHECK",
+            Self::WcoRlsMergeDeleteCheck => "WCO_RLS_MERGE_DELETE_CHECK",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "WCOKIND_UNDEFINED" => Some(Self::WcokindUndefined),
+            "WCO_VIEW_CHECK" => Some(Self::WcoViewCheck),
+            "WCO_RLS_INSERT_CHECK" => Some(Self::WcoRlsInsertCheck),
+            "WCO_RLS_UPDATE_CHECK" => Some(Self::WcoRlsUpdateCheck),
+            "WCO_RLS_CONFLICT_CHECK" => Some(Self::WcoRlsConflictCheck),
+            "WCO_RLS_MERGE_UPDATE_CHECK" => Some(Self::WcoRlsMergeUpdateCheck),
+            "WCO_RLS_MERGE_DELETE_CHECK" => Some(Self::WcoRlsMergeDeleteCheck),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum GroupingSetKind {
+    Undefined = 0,
+    GroupingSetEmpty = 1,
+    GroupingSetSimple = 2,
+    GroupingSetRollup = 3,
+    GroupingSetCube = 4,
+    GroupingSetSets = 5,
+}
+impl GroupingSetKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "GROUPING_SET_KIND_UNDEFINED",
+            Self::GroupingSetEmpty => "GROUPING_SET_EMPTY",
+            Self::GroupingSetSimple => "GROUPING_SET_SIMPLE",
+            Self::GroupingSetRollup => "GROUPING_SET_ROLLUP",
+            Self::GroupingSetCube => "GROUPING_SET_CUBE",
+            Self::GroupingSetSets => "GROUPING_SET_SETS",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "GROUPING_SET_KIND_UNDEFINED" => Some(Self::Undefined),
+            "GROUPING_SET_EMPTY" => Some(Self::GroupingSetEmpty),
+            "GROUPING_SET_SIMPLE" => Some(Self::GroupingSetSimple),
+            "GROUPING_SET_ROLLUP" => Some(Self::GroupingSetRollup),
+            "GROUPING_SET_CUBE" => Some(Self::GroupingSetCube),
+            "GROUPING_SET_SETS" => Some(Self::GroupingSetSets),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum CteMaterialize {
+    CtematerializeUndefined = 0,
+    Default = 1,
+    Always = 2,
+    Never = 3,
+}
+impl CteMaterialize {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::CtematerializeUndefined => "CTEMATERIALIZE_UNDEFINED",
+            Self::Default => "CTEMaterializeDefault",
+            Self::Always => "CTEMaterializeAlways",
+            Self::Never => "CTEMaterializeNever",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "CTEMATERIALIZE_UNDEFINED" => Some(Self::CtematerializeUndefined),
+            "CTEMaterializeDefault" => Some(Self::Default),
+            "CTEMaterializeAlways" => Some(Self::Always),
+            "CTEMaterializeNever" => Some(Self::Never),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonQuotes {
+    Undefined = 0,
+    JsQuotesUnspec = 1,
+    JsQuotesKeep = 2,
+    JsQuotesOmit = 3,
+}
+impl JsonQuotes {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_QUOTES_UNDEFINED",
+            Self::JsQuotesUnspec => "JS_QUOTES_UNSPEC",
+            Self::JsQuotesKeep => "JS_QUOTES_KEEP",
+            Self::JsQuotesOmit => "JS_QUOTES_OMIT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_QUOTES_UNDEFINED" => Some(Self::Undefined),
+            "JS_QUOTES_UNSPEC" => Some(Self::JsQuotesUnspec),
+            "JS_QUOTES_KEEP" => Some(Self::JsQuotesKeep),
+            "JS_QUOTES_OMIT" => Some(Self::JsQuotesOmit),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonTableColumnType {
+    Undefined = 0,
+    JtcForOrdinality = 1,
+    JtcRegular = 2,
+    JtcExists = 3,
+    JtcFormatted = 4,
+    JtcNested = 5,
+}
+impl JsonTableColumnType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_TABLE_COLUMN_TYPE_UNDEFINED",
+            Self::JtcForOrdinality => "JTC_FOR_ORDINALITY",
+            Self::JtcRegular => "JTC_REGULAR",
+            Self::JtcExists => "JTC_EXISTS",
+            Self::JtcFormatted => "JTC_FORMATTED",
+            Self::JtcNested => "JTC_NESTED",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_TABLE_COLUMN_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "JTC_FOR_ORDINALITY" => Some(Self::JtcForOrdinality),
+            "JTC_REGULAR" => Some(Self::JtcRegular),
+            "JTC_EXISTS" => Some(Self::JtcExists),
+            "JTC_FORMATTED" => Some(Self::JtcFormatted),
+            "JTC_NESTED" => Some(Self::JtcNested),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum SetOperation {
+    Undefined = 0,
+    SetopNone = 1,
+    SetopUnion = 2,
+    SetopIntersect = 3,
+    SetopExcept = 4,
+}
+impl SetOperation {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "SET_OPERATION_UNDEFINED",
+            Self::SetopNone => "SETOP_NONE",
+            Self::SetopUnion => "SETOP_UNION",
+            Self::SetopIntersect => "SETOP_INTERSECT",
+            Self::SetopExcept => "SETOP_EXCEPT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "SET_OPERATION_UNDEFINED" => Some(Self::Undefined),
+            "SETOP_NONE" => Some(Self::SetopNone),
+            "SETOP_UNION" => Some(Self::SetopUnion),
+            "SETOP_INTERSECT" => Some(Self::SetopIntersect),
+            "SETOP_EXCEPT" => Some(Self::SetopExcept),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum ObjectType {
+    Undefined = 0,
+    ObjectAccessMethod = 1,
+    ObjectAggregate = 2,
+    ObjectAmop = 3,
+    ObjectAmproc = 4,
+    ObjectAttribute = 5,
+    ObjectCast = 6,
+    ObjectColumn = 7,
+    ObjectCollation = 8,
+    ObjectConversion = 9,
+    ObjectDatabase = 10,
+    ObjectDefault = 11,
+    ObjectDefacl = 12,
+    ObjectDomain = 13,
+    ObjectDomconstraint = 14,
+    ObjectEventTrigger = 15,
+    ObjectExtension = 16,
+    ObjectFdw = 17,
+    ObjectForeignServer = 18,
+    ObjectForeignTable = 19,
+    ObjectFunction = 20,
+    ObjectIndex = 21,
+    ObjectLanguage = 22,
+    ObjectLargeobject = 23,
+    ObjectMatview = 24,
+    ObjectOpclass = 25,
+    ObjectOperator = 26,
+    ObjectOpfamily = 27,
+    ObjectParameterAcl = 28,
+    ObjectPolicy = 29,
+    ObjectProcedure = 30,
+    ObjectPublication = 31,
+    ObjectPublicationNamespace = 32,
+    ObjectPublicationRel = 33,
+    ObjectRole = 34,
+    ObjectRoutine = 35,
+    ObjectRule = 36,
+    ObjectSchema = 37,
+    ObjectSequence = 38,
+    ObjectSubscription = 39,
+    ObjectStatisticExt = 40,
+    ObjectTabconstraint = 41,
+    ObjectTable = 42,
+    ObjectTablespace = 43,
+    ObjectTransform = 44,
+    ObjectTrigger = 45,
+    ObjectTsconfiguration = 46,
+    ObjectTsdictionary = 47,
+    ObjectTsparser = 48,
+    ObjectTstemplate = 49,
+    ObjectType = 50,
+    ObjectUserMapping = 51,
+    ObjectView = 52,
+}
+impl ObjectType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "OBJECT_TYPE_UNDEFINED",
+            Self::ObjectAccessMethod => "OBJECT_ACCESS_METHOD",
+            Self::ObjectAggregate => "OBJECT_AGGREGATE",
+            Self::ObjectAmop => "OBJECT_AMOP",
+            Self::ObjectAmproc => "OBJECT_AMPROC",
+            Self::ObjectAttribute => "OBJECT_ATTRIBUTE",
+            Self::ObjectCast => "OBJECT_CAST",
+            Self::ObjectColumn => "OBJECT_COLUMN",
+            Self::ObjectCollation => "OBJECT_COLLATION",
+            Self::ObjectConversion => "OBJECT_CONVERSION",
+            Self::ObjectDatabase => "OBJECT_DATABASE",
+            Self::ObjectDefault => "OBJECT_DEFAULT",
+            Self::ObjectDefacl => "OBJECT_DEFACL",
+            Self::ObjectDomain => "OBJECT_DOMAIN",
+            Self::ObjectDomconstraint => "OBJECT_DOMCONSTRAINT",
+            Self::ObjectEventTrigger => "OBJECT_EVENT_TRIGGER",
+            Self::ObjectExtension => "OBJECT_EXTENSION",
+            Self::ObjectFdw => "OBJECT_FDW",
+            Self::ObjectForeignServer => "OBJECT_FOREIGN_SERVER",
+            Self::ObjectForeignTable => "OBJECT_FOREIGN_TABLE",
+            Self::ObjectFunction => "OBJECT_FUNCTION",
+            Self::ObjectIndex => "OBJECT_INDEX",
+            Self::ObjectLanguage => "OBJECT_LANGUAGE",
+            Self::ObjectLargeobject => "OBJECT_LARGEOBJECT",
+            Self::ObjectMatview => "OBJECT_MATVIEW",
+            Self::ObjectOpclass => "OBJECT_OPCLASS",
+            Self::ObjectOperator => "OBJECT_OPERATOR",
+            Self::ObjectOpfamily => "OBJECT_OPFAMILY",
+            Self::ObjectParameterAcl => "OBJECT_PARAMETER_ACL",
+            Self::ObjectPolicy => "OBJECT_POLICY",
+            Self::ObjectProcedure => "OBJECT_PROCEDURE",
+            Self::ObjectPublication => "OBJECT_PUBLICATION",
+            Self::ObjectPublicationNamespace => "OBJECT_PUBLICATION_NAMESPACE",
+            Self::ObjectPublicationRel => "OBJECT_PUBLICATION_REL",
+            Self::ObjectRole => "OBJECT_ROLE",
+            Self::ObjectRoutine => "OBJECT_ROUTINE",
+            Self::ObjectRule => "OBJECT_RULE",
+            Self::ObjectSchema => "OBJECT_SCHEMA",
+            Self::ObjectSequence => "OBJECT_SEQUENCE",
+            Self::ObjectSubscription => "OBJECT_SUBSCRIPTION",
+            Self::ObjectStatisticExt => "OBJECT_STATISTIC_EXT",
+            Self::ObjectTabconstraint => "OBJECT_TABCONSTRAINT",
+            Self::ObjectTable => "OBJECT_TABLE",
+            Self::ObjectTablespace => "OBJECT_TABLESPACE",
+            Self::ObjectTransform => "OBJECT_TRANSFORM",
+            Self::ObjectTrigger => "OBJECT_TRIGGER",
+            Self::ObjectTsconfiguration => "OBJECT_TSCONFIGURATION",
+            Self::ObjectTsdictionary => "OBJECT_TSDICTIONARY",
+            Self::ObjectTsparser => "OBJECT_TSPARSER",
+            Self::ObjectTstemplate => "OBJECT_TSTEMPLATE",
+            Self::ObjectType => "OBJECT_TYPE",
+            Self::ObjectUserMapping => "OBJECT_USER_MAPPING",
+            Self::ObjectView => "OBJECT_VIEW",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "OBJECT_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "OBJECT_ACCESS_METHOD" => Some(Self::ObjectAccessMethod),
+            "OBJECT_AGGREGATE" => Some(Self::ObjectAggregate),
+            "OBJECT_AMOP" => Some(Self::ObjectAmop),
+            "OBJECT_AMPROC" => Some(Self::ObjectAmproc),
+            "OBJECT_ATTRIBUTE" => Some(Self::ObjectAttribute),
+            "OBJECT_CAST" => Some(Self::ObjectCast),
+            "OBJECT_COLUMN" => Some(Self::ObjectColumn),
+            "OBJECT_COLLATION" => Some(Self::ObjectCollation),
+            "OBJECT_CONVERSION" => Some(Self::ObjectConversion),
+            "OBJECT_DATABASE" => Some(Self::ObjectDatabase),
+            "OBJECT_DEFAULT" => Some(Self::ObjectDefault),
+            "OBJECT_DEFACL" => Some(Self::ObjectDefacl),
+            "OBJECT_DOMAIN" => Some(Self::ObjectDomain),
+            "OBJECT_DOMCONSTRAINT" => Some(Self::ObjectDomconstraint),
+            "OBJECT_EVENT_TRIGGER" => Some(Self::ObjectEventTrigger),
+            "OBJECT_EXTENSION" => Some(Self::ObjectExtension),
+            "OBJECT_FDW" => Some(Self::ObjectFdw),
+            "OBJECT_FOREIGN_SERVER" => Some(Self::ObjectForeignServer),
+            "OBJECT_FOREIGN_TABLE" => Some(Self::ObjectForeignTable),
+            "OBJECT_FUNCTION" => Some(Self::ObjectFunction),
+            "OBJECT_INDEX" => Some(Self::ObjectIndex),
+            "OBJECT_LANGUAGE" => Some(Self::ObjectLanguage),
+            "OBJECT_LARGEOBJECT" => Some(Self::ObjectLargeobject),
+            "OBJECT_MATVIEW" => Some(Self::ObjectMatview),
+            "OBJECT_OPCLASS" => Some(Self::ObjectOpclass),
+            "OBJECT_OPERATOR" => Some(Self::ObjectOperator),
+            "OBJECT_OPFAMILY" => Some(Self::ObjectOpfamily),
+            "OBJECT_PARAMETER_ACL" => Some(Self::ObjectParameterAcl),
+            "OBJECT_POLICY" => Some(Self::ObjectPolicy),
+            "OBJECT_PROCEDURE" => Some(Self::ObjectProcedure),
+            "OBJECT_PUBLICATION" => Some(Self::ObjectPublication),
+            "OBJECT_PUBLICATION_NAMESPACE" => Some(Self::ObjectPublicationNamespace),
+            "OBJECT_PUBLICATION_REL" => Some(Self::ObjectPublicationRel),
+            "OBJECT_ROLE" => Some(Self::ObjectRole),
+            "OBJECT_ROUTINE" => Some(Self::ObjectRoutine),
+            "OBJECT_RULE" => Some(Self::ObjectRule),
+            "OBJECT_SCHEMA" => Some(Self::ObjectSchema),
+            "OBJECT_SEQUENCE" => Some(Self::ObjectSequence),
+            "OBJECT_SUBSCRIPTION" => Some(Self::ObjectSubscription),
+            "OBJECT_STATISTIC_EXT" => Some(Self::ObjectStatisticExt),
+            "OBJECT_TABCONSTRAINT" => Some(Self::ObjectTabconstraint),
+            "OBJECT_TABLE" => Some(Self::ObjectTable),
+            "OBJECT_TABLESPACE" => Some(Self::ObjectTablespace),
+            "OBJECT_TRANSFORM" => Some(Self::ObjectTransform),
+            "OBJECT_TRIGGER" => Some(Self::ObjectTrigger),
+            "OBJECT_TSCONFIGURATION" => Some(Self::ObjectTsconfiguration),
+            "OBJECT_TSDICTIONARY" => Some(Self::ObjectTsdictionary),
+            "OBJECT_TSPARSER" => Some(Self::ObjectTsparser),
+            "OBJECT_TSTEMPLATE" => Some(Self::ObjectTstemplate),
+            "OBJECT_TYPE" => Some(Self::ObjectType),
+            "OBJECT_USER_MAPPING" => Some(Self::ObjectUserMapping),
+            "OBJECT_VIEW" => Some(Self::ObjectView),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum DropBehavior {
+    Undefined = 0,
+    DropRestrict = 1,
+    DropCascade = 2,
+}
+impl DropBehavior {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "DROP_BEHAVIOR_UNDEFINED",
+            Self::DropRestrict => "DROP_RESTRICT",
+            Self::DropCascade => "DROP_CASCADE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "DROP_BEHAVIOR_UNDEFINED" => Some(Self::Undefined),
+            "DROP_RESTRICT" => Some(Self::DropRestrict),
+            "DROP_CASCADE" => Some(Self::DropCascade),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum AlterTableType {
+    Undefined = 0,
+    AtAddColumn = 1,
+    AtAddColumnToView = 2,
+    AtColumnDefault = 3,
+    AtCookedColumnDefault = 4,
+    AtDropNotNull = 5,
+    AtSetNotNull = 6,
+    AtSetExpression = 7,
+    AtDropExpression = 8,
+    AtCheckNotNull = 9,
+    AtSetStatistics = 10,
+    AtSetOptions = 11,
+    AtResetOptions = 12,
+    AtSetStorage = 13,
+    AtSetCompression = 14,
+    AtDropColumn = 15,
+    AtAddIndex = 16,
+    AtReAddIndex = 17,
+    AtAddConstraint = 18,
+    AtReAddConstraint = 19,
+    AtReAddDomainConstraint = 20,
+    AtAlterConstraint = 21,
+    AtValidateConstraint = 22,
+    AtAddIndexConstraint = 23,
+    AtDropConstraint = 24,
+    AtReAddComment = 25,
+    AtAlterColumnType = 26,
+    AtAlterColumnGenericOptions = 27,
+    AtChangeOwner = 28,
+    AtClusterOn = 29,
+    AtDropCluster = 30,
+    AtSetLogged = 31,
+    AtSetUnLogged = 32,
+    AtDropOids = 33,
+    AtSetAccessMethod = 34,
+    AtSetTableSpace = 35,
+    AtSetRelOptions = 36,
+    AtResetRelOptions = 37,
+    AtReplaceRelOptions = 38,
+    AtEnableTrig = 39,
+    AtEnableAlwaysTrig = 40,
+    AtEnableReplicaTrig = 41,
+    AtDisableTrig = 42,
+    AtEnableTrigAll = 43,
+    AtDisableTrigAll = 44,
+    AtEnableTrigUser = 45,
+    AtDisableTrigUser = 46,
+    AtEnableRule = 47,
+    AtEnableAlwaysRule = 48,
+    AtEnableReplicaRule = 49,
+    AtDisableRule = 50,
+    AtAddInherit = 51,
+    AtDropInherit = 52,
+    AtAddOf = 53,
+    AtDropOf = 54,
+    AtReplicaIdentity = 55,
+    AtEnableRowSecurity = 56,
+    AtDisableRowSecurity = 57,
+    AtForceRowSecurity = 58,
+    AtNoForceRowSecurity = 59,
+    AtGenericOptions = 60,
+    AtAttachPartition = 61,
+    AtDetachPartition = 62,
+    AtDetachPartitionFinalize = 63,
+    AtAddIdentity = 64,
+    AtSetIdentity = 65,
+    AtDropIdentity = 66,
+    AtReAddStatistics = 67,
+}
+impl AlterTableType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "ALTER_TABLE_TYPE_UNDEFINED",
+            Self::AtAddColumn => "AT_AddColumn",
+            Self::AtAddColumnToView => "AT_AddColumnToView",
+            Self::AtColumnDefault => "AT_ColumnDefault",
+            Self::AtCookedColumnDefault => "AT_CookedColumnDefault",
+            Self::AtDropNotNull => "AT_DropNotNull",
+            Self::AtSetNotNull => "AT_SetNotNull",
+            Self::AtSetExpression => "AT_SetExpression",
+            Self::AtDropExpression => "AT_DropExpression",
+            Self::AtCheckNotNull => "AT_CheckNotNull",
+            Self::AtSetStatistics => "AT_SetStatistics",
+            Self::AtSetOptions => "AT_SetOptions",
+            Self::AtResetOptions => "AT_ResetOptions",
+            Self::AtSetStorage => "AT_SetStorage",
+            Self::AtSetCompression => "AT_SetCompression",
+            Self::AtDropColumn => "AT_DropColumn",
+            Self::AtAddIndex => "AT_AddIndex",
+            Self::AtReAddIndex => "AT_ReAddIndex",
+            Self::AtAddConstraint => "AT_AddConstraint",
+            Self::AtReAddConstraint => "AT_ReAddConstraint",
+            Self::AtReAddDomainConstraint => "AT_ReAddDomainConstraint",
+            Self::AtAlterConstraint => "AT_AlterConstraint",
+            Self::AtValidateConstraint => "AT_ValidateConstraint",
+            Self::AtAddIndexConstraint => "AT_AddIndexConstraint",
+            Self::AtDropConstraint => "AT_DropConstraint",
+            Self::AtReAddComment => "AT_ReAddComment",
+            Self::AtAlterColumnType => "AT_AlterColumnType",
+            Self::AtAlterColumnGenericOptions => "AT_AlterColumnGenericOptions",
+            Self::AtChangeOwner => "AT_ChangeOwner",
+            Self::AtClusterOn => "AT_ClusterOn",
+            Self::AtDropCluster => "AT_DropCluster",
+            Self::AtSetLogged => "AT_SetLogged",
+            Self::AtSetUnLogged => "AT_SetUnLogged",
+            Self::AtDropOids => "AT_DropOids",
+            Self::AtSetAccessMethod => "AT_SetAccessMethod",
+            Self::AtSetTableSpace => "AT_SetTableSpace",
+            Self::AtSetRelOptions => "AT_SetRelOptions",
+            Self::AtResetRelOptions => "AT_ResetRelOptions",
+            Self::AtReplaceRelOptions => "AT_ReplaceRelOptions",
+            Self::AtEnableTrig => "AT_EnableTrig",
+            Self::AtEnableAlwaysTrig => "AT_EnableAlwaysTrig",
+            Self::AtEnableReplicaTrig => "AT_EnableReplicaTrig",
+            Self::AtDisableTrig => "AT_DisableTrig",
+            Self::AtEnableTrigAll => "AT_EnableTrigAll",
+            Self::AtDisableTrigAll => "AT_DisableTrigAll",
+            Self::AtEnableTrigUser => "AT_EnableTrigUser",
+            Self::AtDisableTrigUser => "AT_DisableTrigUser",
+            Self::AtEnableRule => "AT_EnableRule",
+            Self::AtEnableAlwaysRule => "AT_EnableAlwaysRule",
+            Self::AtEnableReplicaRule => "AT_EnableReplicaRule",
+            Self::AtDisableRule => "AT_DisableRule",
+            Self::AtAddInherit => "AT_AddInherit",
+            Self::AtDropInherit => "AT_DropInherit",
+            Self::AtAddOf => "AT_AddOf",
+            Self::AtDropOf => "AT_DropOf",
+            Self::AtReplicaIdentity => "AT_ReplicaIdentity",
+            Self::AtEnableRowSecurity => "AT_EnableRowSecurity",
+            Self::AtDisableRowSecurity => "AT_DisableRowSecurity",
+            Self::AtForceRowSecurity => "AT_ForceRowSecurity",
+            Self::AtNoForceRowSecurity => "AT_NoForceRowSecurity",
+            Self::AtGenericOptions => "AT_GenericOptions",
+            Self::AtAttachPartition => "AT_AttachPartition",
+            Self::AtDetachPartition => "AT_DetachPartition",
+            Self::AtDetachPartitionFinalize => "AT_DetachPartitionFinalize",
+            Self::AtAddIdentity => "AT_AddIdentity",
+            Self::AtSetIdentity => "AT_SetIdentity",
+            Self::AtDropIdentity => "AT_DropIdentity",
+            Self::AtReAddStatistics => "AT_ReAddStatistics",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ALTER_TABLE_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "AT_AddColumn" => Some(Self::AtAddColumn),
+            "AT_AddColumnToView" => Some(Self::AtAddColumnToView),
+            "AT_ColumnDefault" => Some(Self::AtColumnDefault),
+            "AT_CookedColumnDefault" => Some(Self::AtCookedColumnDefault),
+            "AT_DropNotNull" => Some(Self::AtDropNotNull),
+            "AT_SetNotNull" => Some(Self::AtSetNotNull),
+            "AT_SetExpression" => Some(Self::AtSetExpression),
+            "AT_DropExpression" => Some(Self::AtDropExpression),
+            "AT_CheckNotNull" => Some(Self::AtCheckNotNull),
+            "AT_SetStatistics" => Some(Self::AtSetStatistics),
+            "AT_SetOptions" => Some(Self::AtSetOptions),
+            "AT_ResetOptions" => Some(Self::AtResetOptions),
+            "AT_SetStorage" => Some(Self::AtSetStorage),
+            "AT_SetCompression" => Some(Self::AtSetCompression),
+            "AT_DropColumn" => Some(Self::AtDropColumn),
+            "AT_AddIndex" => Some(Self::AtAddIndex),
+            "AT_ReAddIndex" => Some(Self::AtReAddIndex),
+            "AT_AddConstraint" => Some(Self::AtAddConstraint),
+            "AT_ReAddConstraint" => Some(Self::AtReAddConstraint),
+            "AT_ReAddDomainConstraint" => Some(Self::AtReAddDomainConstraint),
+            "AT_AlterConstraint" => Some(Self::AtAlterConstraint),
+            "AT_ValidateConstraint" => Some(Self::AtValidateConstraint),
+            "AT_AddIndexConstraint" => Some(Self::AtAddIndexConstraint),
+            "AT_DropConstraint" => Some(Self::AtDropConstraint),
+            "AT_ReAddComment" => Some(Self::AtReAddComment),
+            "AT_AlterColumnType" => Some(Self::AtAlterColumnType),
+            "AT_AlterColumnGenericOptions" => Some(Self::AtAlterColumnGenericOptions),
+            "AT_ChangeOwner" => Some(Self::AtChangeOwner),
+            "AT_ClusterOn" => Some(Self::AtClusterOn),
+            "AT_DropCluster" => Some(Self::AtDropCluster),
+            "AT_SetLogged" => Some(Self::AtSetLogged),
+            "AT_SetUnLogged" => Some(Self::AtSetUnLogged),
+            "AT_DropOids" => Some(Self::AtDropOids),
+            "AT_SetAccessMethod" => Some(Self::AtSetAccessMethod),
+            "AT_SetTableSpace" => Some(Self::AtSetTableSpace),
+            "AT_SetRelOptions" => Some(Self::AtSetRelOptions),
+            "AT_ResetRelOptions" => Some(Self::AtResetRelOptions),
+            "AT_ReplaceRelOptions" => Some(Self::AtReplaceRelOptions),
+            "AT_EnableTrig" => Some(Self::AtEnableTrig),
+            "AT_EnableAlwaysTrig" => Some(Self::AtEnableAlwaysTrig),
+            "AT_EnableReplicaTrig" => Some(Self::AtEnableReplicaTrig),
+            "AT_DisableTrig" => Some(Self::AtDisableTrig),
+            "AT_EnableTrigAll" => Some(Self::AtEnableTrigAll),
+            "AT_DisableTrigAll" => Some(Self::AtDisableTrigAll),
+            "AT_EnableTrigUser" => Some(Self::AtEnableTrigUser),
+            "AT_DisableTrigUser" => Some(Self::AtDisableTrigUser),
+            "AT_EnableRule" => Some(Self::AtEnableRule),
+            "AT_EnableAlwaysRule" => Some(Self::AtEnableAlwaysRule),
+            "AT_EnableReplicaRule" => Some(Self::AtEnableReplicaRule),
+            "AT_DisableRule" => Some(Self::AtDisableRule),
+            "AT_AddInherit" => Some(Self::AtAddInherit),
+            "AT_DropInherit" => Some(Self::AtDropInherit),
+            "AT_AddOf" => Some(Self::AtAddOf),
+            "AT_DropOf" => Some(Self::AtDropOf),
+            "AT_ReplicaIdentity" => Some(Self::AtReplicaIdentity),
+            "AT_EnableRowSecurity" => Some(Self::AtEnableRowSecurity),
+            "AT_DisableRowSecurity" => Some(Self::AtDisableRowSecurity),
+            "AT_ForceRowSecurity" => Some(Self::AtForceRowSecurity),
+            "AT_NoForceRowSecurity" => Some(Self::AtNoForceRowSecurity),
+            "AT_GenericOptions" => Some(Self::AtGenericOptions),
+            "AT_AttachPartition" => Some(Self::AtAttachPartition),
+            "AT_DetachPartition" => Some(Self::AtDetachPartition),
+            "AT_DetachPartitionFinalize" => Some(Self::AtDetachPartitionFinalize),
+            "AT_AddIdentity" => Some(Self::AtAddIdentity),
+            "AT_SetIdentity" => Some(Self::AtSetIdentity),
+            "AT_DropIdentity" => Some(Self::AtDropIdentity),
+            "AT_ReAddStatistics" => Some(Self::AtReAddStatistics),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum GrantTargetType {
+    Undefined = 0,
+    AclTargetObject = 1,
+    AclTargetAllInSchema = 2,
+    AclTargetDefaults = 3,
+}
+impl GrantTargetType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "GRANT_TARGET_TYPE_UNDEFINED",
+            Self::AclTargetObject => "ACL_TARGET_OBJECT",
+            Self::AclTargetAllInSchema => "ACL_TARGET_ALL_IN_SCHEMA",
+            Self::AclTargetDefaults => "ACL_TARGET_DEFAULTS",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "GRANT_TARGET_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "ACL_TARGET_OBJECT" => Some(Self::AclTargetObject),
+            "ACL_TARGET_ALL_IN_SCHEMA" => Some(Self::AclTargetAllInSchema),
+            "ACL_TARGET_DEFAULTS" => Some(Self::AclTargetDefaults),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum VariableSetKind {
+    Undefined = 0,
+    VarSetValue = 1,
+    VarSetDefault = 2,
+    VarSetCurrent = 3,
+    VarSetMulti = 4,
+    VarReset = 5,
+    VarResetAll = 6,
+}
+impl VariableSetKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "VARIABLE_SET_KIND_UNDEFINED",
+            Self::VarSetValue => "VAR_SET_VALUE",
+            Self::VarSetDefault => "VAR_SET_DEFAULT",
+            Self::VarSetCurrent => "VAR_SET_CURRENT",
+            Self::VarSetMulti => "VAR_SET_MULTI",
+            Self::VarReset => "VAR_RESET",
+            Self::VarResetAll => "VAR_RESET_ALL",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "VARIABLE_SET_KIND_UNDEFINED" => Some(Self::Undefined),
+            "VAR_SET_VALUE" => Some(Self::VarSetValue),
+            "VAR_SET_DEFAULT" => Some(Self::VarSetDefault),
+            "VAR_SET_CURRENT" => Some(Self::VarSetCurrent),
+            "VAR_SET_MULTI" => Some(Self::VarSetMulti),
+            "VAR_RESET" => Some(Self::VarReset),
+            "VAR_RESET_ALL" => Some(Self::VarResetAll),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum ConstrType {
+    Undefined = 0,
+    ConstrNull = 1,
+    ConstrNotnull = 2,
+    ConstrDefault = 3,
+    ConstrIdentity = 4,
+    ConstrGenerated = 5,
+    ConstrCheck = 6,
+    ConstrPrimary = 7,
+    ConstrUnique = 8,
+    ConstrExclusion = 9,
+    ConstrForeign = 10,
+    ConstrAttrDeferrable = 11,
+    ConstrAttrNotDeferrable = 12,
+    ConstrAttrDeferred = 13,
+    ConstrAttrImmediate = 14,
+}
+impl ConstrType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "CONSTR_TYPE_UNDEFINED",
+            Self::ConstrNull => "CONSTR_NULL",
+            Self::ConstrNotnull => "CONSTR_NOTNULL",
+            Self::ConstrDefault => "CONSTR_DEFAULT",
+            Self::ConstrIdentity => "CONSTR_IDENTITY",
+            Self::ConstrGenerated => "CONSTR_GENERATED",
+            Self::ConstrCheck => "CONSTR_CHECK",
+            Self::ConstrPrimary => "CONSTR_PRIMARY",
+            Self::ConstrUnique => "CONSTR_UNIQUE",
+            Self::ConstrExclusion => "CONSTR_EXCLUSION",
+            Self::ConstrForeign => "CONSTR_FOREIGN",
+            Self::ConstrAttrDeferrable => "CONSTR_ATTR_DEFERRABLE",
+            Self::ConstrAttrNotDeferrable => "CONSTR_ATTR_NOT_DEFERRABLE",
+            Self::ConstrAttrDeferred => "CONSTR_ATTR_DEFERRED",
+            Self::ConstrAttrImmediate => "CONSTR_ATTR_IMMEDIATE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "CONSTR_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "CONSTR_NULL" => Some(Self::ConstrNull),
+            "CONSTR_NOTNULL" => Some(Self::ConstrNotnull),
+            "CONSTR_DEFAULT" => Some(Self::ConstrDefault),
+            "CONSTR_IDENTITY" => Some(Self::ConstrIdentity),
+            "CONSTR_GENERATED" => Some(Self::ConstrGenerated),
+            "CONSTR_CHECK" => Some(Self::ConstrCheck),
+            "CONSTR_PRIMARY" => Some(Self::ConstrPrimary),
+            "CONSTR_UNIQUE" => Some(Self::ConstrUnique),
+            "CONSTR_EXCLUSION" => Some(Self::ConstrExclusion),
+            "CONSTR_FOREIGN" => Some(Self::ConstrForeign),
+            "CONSTR_ATTR_DEFERRABLE" => Some(Self::ConstrAttrDeferrable),
+            "CONSTR_ATTR_NOT_DEFERRABLE" => Some(Self::ConstrAttrNotDeferrable),
+            "CONSTR_ATTR_DEFERRED" => Some(Self::ConstrAttrDeferred),
+            "CONSTR_ATTR_IMMEDIATE" => Some(Self::ConstrAttrImmediate),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum ImportForeignSchemaType {
+    Undefined = 0,
+    FdwImportSchemaAll = 1,
+    FdwImportSchemaLimitTo = 2,
+    FdwImportSchemaExcept = 3,
+}
+impl ImportForeignSchemaType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "IMPORT_FOREIGN_SCHEMA_TYPE_UNDEFINED",
+            Self::FdwImportSchemaAll => "FDW_IMPORT_SCHEMA_ALL",
+            Self::FdwImportSchemaLimitTo => "FDW_IMPORT_SCHEMA_LIMIT_TO",
+            Self::FdwImportSchemaExcept => "FDW_IMPORT_SCHEMA_EXCEPT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "IMPORT_FOREIGN_SCHEMA_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "FDW_IMPORT_SCHEMA_ALL" => Some(Self::FdwImportSchemaAll),
+            "FDW_IMPORT_SCHEMA_LIMIT_TO" => Some(Self::FdwImportSchemaLimitTo),
+            "FDW_IMPORT_SCHEMA_EXCEPT" => Some(Self::FdwImportSchemaExcept),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum RoleStmtType {
+    Undefined = 0,
+    RolestmtRole = 1,
+    RolestmtUser = 2,
+    RolestmtGroup = 3,
+}
+impl RoleStmtType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "ROLE_STMT_TYPE_UNDEFINED",
+            Self::RolestmtRole => "ROLESTMT_ROLE",
+            Self::RolestmtUser => "ROLESTMT_USER",
+            Self::RolestmtGroup => "ROLESTMT_GROUP",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ROLE_STMT_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "ROLESTMT_ROLE" => Some(Self::RolestmtRole),
+            "ROLESTMT_USER" => Some(Self::RolestmtUser),
+            "ROLESTMT_GROUP" => Some(Self::RolestmtGroup),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum FetchDirection {
+    Undefined = 0,
+    FetchForward = 1,
+    FetchBackward = 2,
+    FetchAbsolute = 3,
+    FetchRelative = 4,
+}
+impl FetchDirection {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "FETCH_DIRECTION_UNDEFINED",
+            Self::FetchForward => "FETCH_FORWARD",
+            Self::FetchBackward => "FETCH_BACKWARD",
+            Self::FetchAbsolute => "FETCH_ABSOLUTE",
+            Self::FetchRelative => "FETCH_RELATIVE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "FETCH_DIRECTION_UNDEFINED" => Some(Self::Undefined),
+            "FETCH_FORWARD" => Some(Self::FetchForward),
+            "FETCH_BACKWARD" => Some(Self::FetchBackward),
+            "FETCH_ABSOLUTE" => Some(Self::FetchAbsolute),
+            "FETCH_RELATIVE" => Some(Self::FetchRelative),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum FunctionParameterMode {
+    Undefined = 0,
+    FuncParamIn = 1,
+    FuncParamOut = 2,
+    FuncParamInout = 3,
+    FuncParamVariadic = 4,
+    FuncParamTable = 5,
+    FuncParamDefault = 6,
+}
+impl FunctionParameterMode {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "FUNCTION_PARAMETER_MODE_UNDEFINED",
+            Self::FuncParamIn => "FUNC_PARAM_IN",
+            Self::FuncParamOut => "FUNC_PARAM_OUT",
+            Self::FuncParamInout => "FUNC_PARAM_INOUT",
+            Self::FuncParamVariadic => "FUNC_PARAM_VARIADIC",
+            Self::FuncParamTable => "FUNC_PARAM_TABLE",
+            Self::FuncParamDefault => "FUNC_PARAM_DEFAULT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "FUNCTION_PARAMETER_MODE_UNDEFINED" => Some(Self::Undefined),
+            "FUNC_PARAM_IN" => Some(Self::FuncParamIn),
+            "FUNC_PARAM_OUT" => Some(Self::FuncParamOut),
+            "FUNC_PARAM_INOUT" => Some(Self::FuncParamInout),
+            "FUNC_PARAM_VARIADIC" => Some(Self::FuncParamVariadic),
+            "FUNC_PARAM_TABLE" => Some(Self::FuncParamTable),
+            "FUNC_PARAM_DEFAULT" => Some(Self::FuncParamDefault),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum TransactionStmtKind {
+    Undefined = 0,
+    TransStmtBegin = 1,
+    TransStmtStart = 2,
+    TransStmtCommit = 3,
+    TransStmtRollback = 4,
+    TransStmtSavepoint = 5,
+    TransStmtRelease = 6,
+    TransStmtRollbackTo = 7,
+    TransStmtPrepare = 8,
+    TransStmtCommitPrepared = 9,
+    TransStmtRollbackPrepared = 10,
+}
+impl TransactionStmtKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "TRANSACTION_STMT_KIND_UNDEFINED",
+            Self::TransStmtBegin => "TRANS_STMT_BEGIN",
+            Self::TransStmtStart => "TRANS_STMT_START",
+            Self::TransStmtCommit => "TRANS_STMT_COMMIT",
+            Self::TransStmtRollback => "TRANS_STMT_ROLLBACK",
+            Self::TransStmtSavepoint => "TRANS_STMT_SAVEPOINT",
+            Self::TransStmtRelease => "TRANS_STMT_RELEASE",
+            Self::TransStmtRollbackTo => "TRANS_STMT_ROLLBACK_TO",
+            Self::TransStmtPrepare => "TRANS_STMT_PREPARE",
+            Self::TransStmtCommitPrepared => "TRANS_STMT_COMMIT_PREPARED",
+            Self::TransStmtRollbackPrepared => "TRANS_STMT_ROLLBACK_PREPARED",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "TRANSACTION_STMT_KIND_UNDEFINED" => Some(Self::Undefined),
+            "TRANS_STMT_BEGIN" => Some(Self::TransStmtBegin),
+            "TRANS_STMT_START" => Some(Self::TransStmtStart),
+            "TRANS_STMT_COMMIT" => Some(Self::TransStmtCommit),
+            "TRANS_STMT_ROLLBACK" => Some(Self::TransStmtRollback),
+            "TRANS_STMT_SAVEPOINT" => Some(Self::TransStmtSavepoint),
+            "TRANS_STMT_RELEASE" => Some(Self::TransStmtRelease),
+            "TRANS_STMT_ROLLBACK_TO" => Some(Self::TransStmtRollbackTo),
+            "TRANS_STMT_PREPARE" => Some(Self::TransStmtPrepare),
+            "TRANS_STMT_COMMIT_PREPARED" => Some(Self::TransStmtCommitPrepared),
+            "TRANS_STMT_ROLLBACK_PREPARED" => Some(Self::TransStmtRollbackPrepared),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum ViewCheckOption {
+    Undefined = 0,
+    NoCheckOption = 1,
+    LocalCheckOption = 2,
+    CascadedCheckOption = 3,
+}
+impl ViewCheckOption {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "VIEW_CHECK_OPTION_UNDEFINED",
+            Self::NoCheckOption => "NO_CHECK_OPTION",
+            Self::LocalCheckOption => "LOCAL_CHECK_OPTION",
+            Self::CascadedCheckOption => "CASCADED_CHECK_OPTION",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "VIEW_CHECK_OPTION_UNDEFINED" => Some(Self::Undefined),
+            "NO_CHECK_OPTION" => Some(Self::NoCheckOption),
+            "LOCAL_CHECK_OPTION" => Some(Self::LocalCheckOption),
+            "CASCADED_CHECK_OPTION" => Some(Self::CascadedCheckOption),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum DiscardMode {
+    Undefined = 0,
+    DiscardAll = 1,
+    DiscardPlans = 2,
+    DiscardSequences = 3,
+    DiscardTemp = 4,
+}
+impl DiscardMode {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "DISCARD_MODE_UNDEFINED",
+            Self::DiscardAll => "DISCARD_ALL",
+            Self::DiscardPlans => "DISCARD_PLANS",
+            Self::DiscardSequences => "DISCARD_SEQUENCES",
+            Self::DiscardTemp => "DISCARD_TEMP",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "DISCARD_MODE_UNDEFINED" => Some(Self::Undefined),
+            "DISCARD_ALL" => Some(Self::DiscardAll),
+            "DISCARD_PLANS" => Some(Self::DiscardPlans),
+            "DISCARD_SEQUENCES" => Some(Self::DiscardSequences),
+            "DISCARD_TEMP" => Some(Self::DiscardTemp),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum ReindexObjectType {
+    Undefined = 0,
+    ReindexObjectIndex = 1,
+    ReindexObjectTable = 2,
+    ReindexObjectSchema = 3,
+    ReindexObjectSystem = 4,
+    ReindexObjectDatabase = 5,
+}
+impl ReindexObjectType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "REINDEX_OBJECT_TYPE_UNDEFINED",
+            Self::ReindexObjectIndex => "REINDEX_OBJECT_INDEX",
+            Self::ReindexObjectTable => "REINDEX_OBJECT_TABLE",
+            Self::ReindexObjectSchema => "REINDEX_OBJECT_SCHEMA",
+            Self::ReindexObjectSystem => "REINDEX_OBJECT_SYSTEM",
+            Self::ReindexObjectDatabase => "REINDEX_OBJECT_DATABASE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "REINDEX_OBJECT_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "REINDEX_OBJECT_INDEX" => Some(Self::ReindexObjectIndex),
+            "REINDEX_OBJECT_TABLE" => Some(Self::ReindexObjectTable),
+            "REINDEX_OBJECT_SCHEMA" => Some(Self::ReindexObjectSchema),
+            "REINDEX_OBJECT_SYSTEM" => Some(Self::ReindexObjectSystem),
+            "REINDEX_OBJECT_DATABASE" => Some(Self::ReindexObjectDatabase),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum AlterTsConfigType {
+    AlterTsconfigTypeUndefined = 0,
+    AlterTsconfigAddMapping = 1,
+    AlterTsconfigAlterMappingForToken = 2,
+    AlterTsconfigReplaceDict = 3,
+    AlterTsconfigReplaceDictForToken = 4,
+    AlterTsconfigDropMapping = 5,
+}
+impl AlterTsConfigType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::AlterTsconfigTypeUndefined => "ALTER_TSCONFIG_TYPE_UNDEFINED",
+            Self::AlterTsconfigAddMapping => "ALTER_TSCONFIG_ADD_MAPPING",
+            Self::AlterTsconfigAlterMappingForToken => {
+                "ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN"
+            }
+            Self::AlterTsconfigReplaceDict => "ALTER_TSCONFIG_REPLACE_DICT",
+            Self::AlterTsconfigReplaceDictForToken => {
+                "ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN"
+            }
+            Self::AlterTsconfigDropMapping => "ALTER_TSCONFIG_DROP_MAPPING",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ALTER_TSCONFIG_TYPE_UNDEFINED" => Some(Self::AlterTsconfigTypeUndefined),
+            "ALTER_TSCONFIG_ADD_MAPPING" => Some(Self::AlterTsconfigAddMapping),
+            "ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN" => {
+                Some(Self::AlterTsconfigAlterMappingForToken)
+            }
+            "ALTER_TSCONFIG_REPLACE_DICT" => Some(Self::AlterTsconfigReplaceDict),
+            "ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN" => {
+                Some(Self::AlterTsconfigReplaceDictForToken)
+            }
+            "ALTER_TSCONFIG_DROP_MAPPING" => Some(Self::AlterTsconfigDropMapping),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum PublicationObjSpecType {
+    Undefined = 0,
+    PublicationobjTable = 1,
+    PublicationobjTablesInSchema = 2,
+    PublicationobjTablesInCurSchema = 3,
+    PublicationobjContinuation = 4,
+}
+impl PublicationObjSpecType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "PUBLICATION_OBJ_SPEC_TYPE_UNDEFINED",
+            Self::PublicationobjTable => "PUBLICATIONOBJ_TABLE",
+            Self::PublicationobjTablesInSchema => "PUBLICATIONOBJ_TABLES_IN_SCHEMA",
+            Self::PublicationobjTablesInCurSchema => {
+                "PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA"
+            }
+            Self::PublicationobjContinuation => "PUBLICATIONOBJ_CONTINUATION",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "PUBLICATION_OBJ_SPEC_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "PUBLICATIONOBJ_TABLE" => Some(Self::PublicationobjTable),
+            "PUBLICATIONOBJ_TABLES_IN_SCHEMA" => Some(Self::PublicationobjTablesInSchema),
+            "PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA" => {
+                Some(Self::PublicationobjTablesInCurSchema)
+            }
+            "PUBLICATIONOBJ_CONTINUATION" => Some(Self::PublicationobjContinuation),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum AlterPublicationAction {
+    Undefined = 0,
+    ApAddObjects = 1,
+    ApDropObjects = 2,
+    ApSetObjects = 3,
+}
+impl AlterPublicationAction {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "ALTER_PUBLICATION_ACTION_UNDEFINED",
+            Self::ApAddObjects => "AP_AddObjects",
+            Self::ApDropObjects => "AP_DropObjects",
+            Self::ApSetObjects => "AP_SetObjects",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ALTER_PUBLICATION_ACTION_UNDEFINED" => Some(Self::Undefined),
+            "AP_AddObjects" => Some(Self::ApAddObjects),
+            "AP_DropObjects" => Some(Self::ApDropObjects),
+            "AP_SetObjects" => Some(Self::ApSetObjects),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum AlterSubscriptionType {
+    Undefined = 0,
+    AlterSubscriptionOptions = 1,
+    AlterSubscriptionConnection = 2,
+    AlterSubscriptionSetPublication = 3,
+    AlterSubscriptionAddPublication = 4,
+    AlterSubscriptionDropPublication = 5,
+    AlterSubscriptionRefresh = 6,
+    AlterSubscriptionEnabled = 7,
+    AlterSubscriptionSkip = 8,
+}
+impl AlterSubscriptionType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "ALTER_SUBSCRIPTION_TYPE_UNDEFINED",
+            Self::AlterSubscriptionOptions => "ALTER_SUBSCRIPTION_OPTIONS",
+            Self::AlterSubscriptionConnection => "ALTER_SUBSCRIPTION_CONNECTION",
+            Self::AlterSubscriptionSetPublication => "ALTER_SUBSCRIPTION_SET_PUBLICATION",
+            Self::AlterSubscriptionAddPublication => "ALTER_SUBSCRIPTION_ADD_PUBLICATION",
+            Self::AlterSubscriptionDropPublication => {
+                "ALTER_SUBSCRIPTION_DROP_PUBLICATION"
+            }
+            Self::AlterSubscriptionRefresh => "ALTER_SUBSCRIPTION_REFRESH",
+            Self::AlterSubscriptionEnabled => "ALTER_SUBSCRIPTION_ENABLED",
+            Self::AlterSubscriptionSkip => "ALTER_SUBSCRIPTION_SKIP",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ALTER_SUBSCRIPTION_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "ALTER_SUBSCRIPTION_OPTIONS" => Some(Self::AlterSubscriptionOptions),
+            "ALTER_SUBSCRIPTION_CONNECTION" => Some(Self::AlterSubscriptionConnection),
+            "ALTER_SUBSCRIPTION_SET_PUBLICATION" => {
+                Some(Self::AlterSubscriptionSetPublication)
+            }
+            "ALTER_SUBSCRIPTION_ADD_PUBLICATION" => {
+                Some(Self::AlterSubscriptionAddPublication)
+            }
+            "ALTER_SUBSCRIPTION_DROP_PUBLICATION" => {
+                Some(Self::AlterSubscriptionDropPublication)
+            }
+            "ALTER_SUBSCRIPTION_REFRESH" => Some(Self::AlterSubscriptionRefresh),
+            "ALTER_SUBSCRIPTION_ENABLED" => Some(Self::AlterSubscriptionEnabled),
+            "ALTER_SUBSCRIPTION_SKIP" => Some(Self::AlterSubscriptionSkip),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum OverridingKind {
+    Undefined = 0,
+    OverridingNotSet = 1,
+    OverridingUserValue = 2,
+    OverridingSystemValue = 3,
+}
+impl OverridingKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "OVERRIDING_KIND_UNDEFINED",
+            Self::OverridingNotSet => "OVERRIDING_NOT_SET",
+            Self::OverridingUserValue => "OVERRIDING_USER_VALUE",
+            Self::OverridingSystemValue => "OVERRIDING_SYSTEM_VALUE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "OVERRIDING_KIND_UNDEFINED" => Some(Self::Undefined),
+            "OVERRIDING_NOT_SET" => Some(Self::OverridingNotSet),
+            "OVERRIDING_USER_VALUE" => Some(Self::OverridingUserValue),
+            "OVERRIDING_SYSTEM_VALUE" => Some(Self::OverridingSystemValue),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum OnCommitAction {
+    Undefined = 0,
+    OncommitNoop = 1,
+    OncommitPreserveRows = 2,
+    OncommitDeleteRows = 3,
+    OncommitDrop = 4,
+}
+impl OnCommitAction {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "ON_COMMIT_ACTION_UNDEFINED",
+            Self::OncommitNoop => "ONCOMMIT_NOOP",
+            Self::OncommitPreserveRows => "ONCOMMIT_PRESERVE_ROWS",
+            Self::OncommitDeleteRows => "ONCOMMIT_DELETE_ROWS",
+            Self::OncommitDrop => "ONCOMMIT_DROP",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ON_COMMIT_ACTION_UNDEFINED" => Some(Self::Undefined),
+            "ONCOMMIT_NOOP" => Some(Self::OncommitNoop),
+            "ONCOMMIT_PRESERVE_ROWS" => Some(Self::OncommitPreserveRows),
+            "ONCOMMIT_DELETE_ROWS" => Some(Self::OncommitDeleteRows),
+            "ONCOMMIT_DROP" => Some(Self::OncommitDrop),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum TableFuncType {
+    Undefined = 0,
+    TftXmltable = 1,
+    TftJsonTable = 2,
+}
+impl TableFuncType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "TABLE_FUNC_TYPE_UNDEFINED",
+            Self::TftXmltable => "TFT_XMLTABLE",
+            Self::TftJsonTable => "TFT_JSON_TABLE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "TABLE_FUNC_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "TFT_XMLTABLE" => Some(Self::TftXmltable),
+            "TFT_JSON_TABLE" => Some(Self::TftJsonTable),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum ParamKind {
+    Undefined = 0,
+    ParamExtern = 1,
+    ParamExec = 2,
+    ParamSublink = 3,
+    ParamMultiexpr = 4,
+}
+impl ParamKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "PARAM_KIND_UNDEFINED",
+            Self::ParamExtern => "PARAM_EXTERN",
+            Self::ParamExec => "PARAM_EXEC",
+            Self::ParamSublink => "PARAM_SUBLINK",
+            Self::ParamMultiexpr => "PARAM_MULTIEXPR",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "PARAM_KIND_UNDEFINED" => Some(Self::Undefined),
+            "PARAM_EXTERN" => Some(Self::ParamExtern),
+            "PARAM_EXEC" => Some(Self::ParamExec),
+            "PARAM_SUBLINK" => Some(Self::ParamSublink),
+            "PARAM_MULTIEXPR" => Some(Self::ParamMultiexpr),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum CoercionContext {
+    Undefined = 0,
+    CoercionImplicit = 1,
+    CoercionAssignment = 2,
+    CoercionPlpgsql = 3,
+    CoercionExplicit = 4,
+}
+impl CoercionContext {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "COERCION_CONTEXT_UNDEFINED",
+            Self::CoercionImplicit => "COERCION_IMPLICIT",
+            Self::CoercionAssignment => "COERCION_ASSIGNMENT",
+            Self::CoercionPlpgsql => "COERCION_PLPGSQL",
+            Self::CoercionExplicit => "COERCION_EXPLICIT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "COERCION_CONTEXT_UNDEFINED" => Some(Self::Undefined),
+            "COERCION_IMPLICIT" => Some(Self::CoercionImplicit),
+            "COERCION_ASSIGNMENT" => Some(Self::CoercionAssignment),
+            "COERCION_PLPGSQL" => Some(Self::CoercionPlpgsql),
+            "COERCION_EXPLICIT" => Some(Self::CoercionExplicit),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum CoercionForm {
+    Undefined = 0,
+    CoerceExplicitCall = 1,
+    CoerceExplicitCast = 2,
+    CoerceImplicitCast = 3,
+    CoerceSqlSyntax = 4,
+}
+impl CoercionForm {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "COERCION_FORM_UNDEFINED",
+            Self::CoerceExplicitCall => "COERCE_EXPLICIT_CALL",
+            Self::CoerceExplicitCast => "COERCE_EXPLICIT_CAST",
+            Self::CoerceImplicitCast => "COERCE_IMPLICIT_CAST",
+            Self::CoerceSqlSyntax => "COERCE_SQL_SYNTAX",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "COERCION_FORM_UNDEFINED" => Some(Self::Undefined),
+            "COERCE_EXPLICIT_CALL" => Some(Self::CoerceExplicitCall),
+            "COERCE_EXPLICIT_CAST" => Some(Self::CoerceExplicitCast),
+            "COERCE_IMPLICIT_CAST" => Some(Self::CoerceImplicitCast),
+            "COERCE_SQL_SYNTAX" => Some(Self::CoerceSqlSyntax),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum BoolExprType {
+    Undefined = 0,
+    AndExpr = 1,
+    OrExpr = 2,
+    NotExpr = 3,
+}
+impl BoolExprType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "BOOL_EXPR_TYPE_UNDEFINED",
+            Self::AndExpr => "AND_EXPR",
+            Self::OrExpr => "OR_EXPR",
+            Self::NotExpr => "NOT_EXPR",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "BOOL_EXPR_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "AND_EXPR" => Some(Self::AndExpr),
+            "OR_EXPR" => Some(Self::OrExpr),
+            "NOT_EXPR" => Some(Self::NotExpr),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum SubLinkType {
+    Undefined = 0,
+    ExistsSublink = 1,
+    AllSublink = 2,
+    AnySublink = 3,
+    RowcompareSublink = 4,
+    ExprSublink = 5,
+    MultiexprSublink = 6,
+    ArraySublink = 7,
+    CteSublink = 8,
+}
+impl SubLinkType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "SUB_LINK_TYPE_UNDEFINED",
+            Self::ExistsSublink => "EXISTS_SUBLINK",
+            Self::AllSublink => "ALL_SUBLINK",
+            Self::AnySublink => "ANY_SUBLINK",
+            Self::RowcompareSublink => "ROWCOMPARE_SUBLINK",
+            Self::ExprSublink => "EXPR_SUBLINK",
+            Self::MultiexprSublink => "MULTIEXPR_SUBLINK",
+            Self::ArraySublink => "ARRAY_SUBLINK",
+            Self::CteSublink => "CTE_SUBLINK",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "SUB_LINK_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "EXISTS_SUBLINK" => Some(Self::ExistsSublink),
+            "ALL_SUBLINK" => Some(Self::AllSublink),
+            "ANY_SUBLINK" => Some(Self::AnySublink),
+            "ROWCOMPARE_SUBLINK" => Some(Self::RowcompareSublink),
+            "EXPR_SUBLINK" => Some(Self::ExprSublink),
+            "MULTIEXPR_SUBLINK" => Some(Self::MultiexprSublink),
+            "ARRAY_SUBLINK" => Some(Self::ArraySublink),
+            "CTE_SUBLINK" => Some(Self::CteSublink),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum RowCompareType {
+    Undefined = 0,
+    RowcompareLt = 1,
+    RowcompareLe = 2,
+    RowcompareEq = 3,
+    RowcompareGe = 4,
+    RowcompareGt = 5,
+    RowcompareNe = 6,
+}
+impl RowCompareType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "ROW_COMPARE_TYPE_UNDEFINED",
+            Self::RowcompareLt => "ROWCOMPARE_LT",
+            Self::RowcompareLe => "ROWCOMPARE_LE",
+            Self::RowcompareEq => "ROWCOMPARE_EQ",
+            Self::RowcompareGe => "ROWCOMPARE_GE",
+            Self::RowcompareGt => "ROWCOMPARE_GT",
+            Self::RowcompareNe => "ROWCOMPARE_NE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ROW_COMPARE_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "ROWCOMPARE_LT" => Some(Self::RowcompareLt),
+            "ROWCOMPARE_LE" => Some(Self::RowcompareLe),
+            "ROWCOMPARE_EQ" => Some(Self::RowcompareEq),
+            "ROWCOMPARE_GE" => Some(Self::RowcompareGe),
+            "ROWCOMPARE_GT" => Some(Self::RowcompareGt),
+            "ROWCOMPARE_NE" => Some(Self::RowcompareNe),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum MinMaxOp {
+    Undefined = 0,
+    IsGreatest = 1,
+    IsLeast = 2,
+}
+impl MinMaxOp {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "MIN_MAX_OP_UNDEFINED",
+            Self::IsGreatest => "IS_GREATEST",
+            Self::IsLeast => "IS_LEAST",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "MIN_MAX_OP_UNDEFINED" => Some(Self::Undefined),
+            "IS_GREATEST" => Some(Self::IsGreatest),
+            "IS_LEAST" => Some(Self::IsLeast),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum SqlValueFunctionOp {
+    SqlvalueFunctionOpUndefined = 0,
+    SvfopCurrentDate = 1,
+    SvfopCurrentTime = 2,
+    SvfopCurrentTimeN = 3,
+    SvfopCurrentTimestamp = 4,
+    SvfopCurrentTimestampN = 5,
+    SvfopLocaltime = 6,
+    SvfopLocaltimeN = 7,
+    SvfopLocaltimestamp = 8,
+    SvfopLocaltimestampN = 9,
+    SvfopCurrentRole = 10,
+    SvfopCurrentUser = 11,
+    SvfopUser = 12,
+    SvfopSessionUser = 13,
+    SvfopCurrentCatalog = 14,
+    SvfopCurrentSchema = 15,
+}
+impl SqlValueFunctionOp {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::SqlvalueFunctionOpUndefined => "SQLVALUE_FUNCTION_OP_UNDEFINED",
+            Self::SvfopCurrentDate => "SVFOP_CURRENT_DATE",
+            Self::SvfopCurrentTime => "SVFOP_CURRENT_TIME",
+            Self::SvfopCurrentTimeN => "SVFOP_CURRENT_TIME_N",
+            Self::SvfopCurrentTimestamp => "SVFOP_CURRENT_TIMESTAMP",
+            Self::SvfopCurrentTimestampN => "SVFOP_CURRENT_TIMESTAMP_N",
+            Self::SvfopLocaltime => "SVFOP_LOCALTIME",
+            Self::SvfopLocaltimeN => "SVFOP_LOCALTIME_N",
+            Self::SvfopLocaltimestamp => "SVFOP_LOCALTIMESTAMP",
+            Self::SvfopLocaltimestampN => "SVFOP_LOCALTIMESTAMP_N",
+            Self::SvfopCurrentRole => "SVFOP_CURRENT_ROLE",
+            Self::SvfopCurrentUser => "SVFOP_CURRENT_USER",
+            Self::SvfopUser => "SVFOP_USER",
+            Self::SvfopSessionUser => "SVFOP_SESSION_USER",
+            Self::SvfopCurrentCatalog => "SVFOP_CURRENT_CATALOG",
+            Self::SvfopCurrentSchema => "SVFOP_CURRENT_SCHEMA",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "SQLVALUE_FUNCTION_OP_UNDEFINED" => Some(Self::SqlvalueFunctionOpUndefined),
+            "SVFOP_CURRENT_DATE" => Some(Self::SvfopCurrentDate),
+            "SVFOP_CURRENT_TIME" => Some(Self::SvfopCurrentTime),
+            "SVFOP_CURRENT_TIME_N" => Some(Self::SvfopCurrentTimeN),
+            "SVFOP_CURRENT_TIMESTAMP" => Some(Self::SvfopCurrentTimestamp),
+            "SVFOP_CURRENT_TIMESTAMP_N" => Some(Self::SvfopCurrentTimestampN),
+            "SVFOP_LOCALTIME" => Some(Self::SvfopLocaltime),
+            "SVFOP_LOCALTIME_N" => Some(Self::SvfopLocaltimeN),
+            "SVFOP_LOCALTIMESTAMP" => Some(Self::SvfopLocaltimestamp),
+            "SVFOP_LOCALTIMESTAMP_N" => Some(Self::SvfopLocaltimestampN),
+            "SVFOP_CURRENT_ROLE" => Some(Self::SvfopCurrentRole),
+            "SVFOP_CURRENT_USER" => Some(Self::SvfopCurrentUser),
+            "SVFOP_USER" => Some(Self::SvfopUser),
+            "SVFOP_SESSION_USER" => Some(Self::SvfopSessionUser),
+            "SVFOP_CURRENT_CATALOG" => Some(Self::SvfopCurrentCatalog),
+            "SVFOP_CURRENT_SCHEMA" => Some(Self::SvfopCurrentSchema),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum XmlExprOp {
+    Undefined = 0,
+    IsXmlconcat = 1,
+    IsXmlelement = 2,
+    IsXmlforest = 3,
+    IsXmlparse = 4,
+    IsXmlpi = 5,
+    IsXmlroot = 6,
+    IsXmlserialize = 7,
+    IsDocument = 8,
+}
+impl XmlExprOp {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "XML_EXPR_OP_UNDEFINED",
+            Self::IsXmlconcat => "IS_XMLCONCAT",
+            Self::IsXmlelement => "IS_XMLELEMENT",
+            Self::IsXmlforest => "IS_XMLFOREST",
+            Self::IsXmlparse => "IS_XMLPARSE",
+            Self::IsXmlpi => "IS_XMLPI",
+            Self::IsXmlroot => "IS_XMLROOT",
+            Self::IsXmlserialize => "IS_XMLSERIALIZE",
+            Self::IsDocument => "IS_DOCUMENT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "XML_EXPR_OP_UNDEFINED" => Some(Self::Undefined),
+            "IS_XMLCONCAT" => Some(Self::IsXmlconcat),
+            "IS_XMLELEMENT" => Some(Self::IsXmlelement),
+            "IS_XMLFOREST" => Some(Self::IsXmlforest),
+            "IS_XMLPARSE" => Some(Self::IsXmlparse),
+            "IS_XMLPI" => Some(Self::IsXmlpi),
+            "IS_XMLROOT" => Some(Self::IsXmlroot),
+            "IS_XMLSERIALIZE" => Some(Self::IsXmlserialize),
+            "IS_DOCUMENT" => Some(Self::IsDocument),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum XmlOptionType {
+    Undefined = 0,
+    XmloptionDocument = 1,
+    XmloptionContent = 2,
+}
+impl XmlOptionType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "XML_OPTION_TYPE_UNDEFINED",
+            Self::XmloptionDocument => "XMLOPTION_DOCUMENT",
+            Self::XmloptionContent => "XMLOPTION_CONTENT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "XML_OPTION_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "XMLOPTION_DOCUMENT" => Some(Self::XmloptionDocument),
+            "XMLOPTION_CONTENT" => Some(Self::XmloptionContent),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonEncoding {
+    Undefined = 0,
+    JsEncDefault = 1,
+    JsEncUtf8 = 2,
+    JsEncUtf16 = 3,
+    JsEncUtf32 = 4,
+}
+impl JsonEncoding {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_ENCODING_UNDEFINED",
+            Self::JsEncDefault => "JS_ENC_DEFAULT",
+            Self::JsEncUtf8 => "JS_ENC_UTF8",
+            Self::JsEncUtf16 => "JS_ENC_UTF16",
+            Self::JsEncUtf32 => "JS_ENC_UTF32",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_ENCODING_UNDEFINED" => Some(Self::Undefined),
+            "JS_ENC_DEFAULT" => Some(Self::JsEncDefault),
+            "JS_ENC_UTF8" => Some(Self::JsEncUtf8),
+            "JS_ENC_UTF16" => Some(Self::JsEncUtf16),
+            "JS_ENC_UTF32" => Some(Self::JsEncUtf32),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonFormatType {
+    Undefined = 0,
+    JsFormatDefault = 1,
+    JsFormatJson = 2,
+    JsFormatJsonb = 3,
+}
+impl JsonFormatType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_FORMAT_TYPE_UNDEFINED",
+            Self::JsFormatDefault => "JS_FORMAT_DEFAULT",
+            Self::JsFormatJson => "JS_FORMAT_JSON",
+            Self::JsFormatJsonb => "JS_FORMAT_JSONB",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_FORMAT_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "JS_FORMAT_DEFAULT" => Some(Self::JsFormatDefault),
+            "JS_FORMAT_JSON" => Some(Self::JsFormatJson),
+            "JS_FORMAT_JSONB" => Some(Self::JsFormatJsonb),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonConstructorType {
+    Undefined = 0,
+    JsctorJsonObject = 1,
+    JsctorJsonArray = 2,
+    JsctorJsonObjectagg = 3,
+    JsctorJsonArrayagg = 4,
+    JsctorJsonParse = 5,
+    JsctorJsonScalar = 6,
+    JsctorJsonSerialize = 7,
+}
+impl JsonConstructorType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_CONSTRUCTOR_TYPE_UNDEFINED",
+            Self::JsctorJsonObject => "JSCTOR_JSON_OBJECT",
+            Self::JsctorJsonArray => "JSCTOR_JSON_ARRAY",
+            Self::JsctorJsonObjectagg => "JSCTOR_JSON_OBJECTAGG",
+            Self::JsctorJsonArrayagg => "JSCTOR_JSON_ARRAYAGG",
+            Self::JsctorJsonParse => "JSCTOR_JSON_PARSE",
+            Self::JsctorJsonScalar => "JSCTOR_JSON_SCALAR",
+            Self::JsctorJsonSerialize => "JSCTOR_JSON_SERIALIZE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_CONSTRUCTOR_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "JSCTOR_JSON_OBJECT" => Some(Self::JsctorJsonObject),
+            "JSCTOR_JSON_ARRAY" => Some(Self::JsctorJsonArray),
+            "JSCTOR_JSON_OBJECTAGG" => Some(Self::JsctorJsonObjectagg),
+            "JSCTOR_JSON_ARRAYAGG" => Some(Self::JsctorJsonArrayagg),
+            "JSCTOR_JSON_PARSE" => Some(Self::JsctorJsonParse),
+            "JSCTOR_JSON_SCALAR" => Some(Self::JsctorJsonScalar),
+            "JSCTOR_JSON_SERIALIZE" => Some(Self::JsctorJsonSerialize),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonValueType {
+    Undefined = 0,
+    JsTypeAny = 1,
+    JsTypeObject = 2,
+    JsTypeArray = 3,
+    JsTypeScalar = 4,
+}
+impl JsonValueType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_VALUE_TYPE_UNDEFINED",
+            Self::JsTypeAny => "JS_TYPE_ANY",
+            Self::JsTypeObject => "JS_TYPE_OBJECT",
+            Self::JsTypeArray => "JS_TYPE_ARRAY",
+            Self::JsTypeScalar => "JS_TYPE_SCALAR",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_VALUE_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "JS_TYPE_ANY" => Some(Self::JsTypeAny),
+            "JS_TYPE_OBJECT" => Some(Self::JsTypeObject),
+            "JS_TYPE_ARRAY" => Some(Self::JsTypeArray),
+            "JS_TYPE_SCALAR" => Some(Self::JsTypeScalar),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonWrapper {
+    Undefined = 0,
+    JswUnspec = 1,
+    JswNone = 2,
+    JswConditional = 3,
+    JswUnconditional = 4,
+}
+impl JsonWrapper {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_WRAPPER_UNDEFINED",
+            Self::JswUnspec => "JSW_UNSPEC",
+            Self::JswNone => "JSW_NONE",
+            Self::JswConditional => "JSW_CONDITIONAL",
+            Self::JswUnconditional => "JSW_UNCONDITIONAL",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_WRAPPER_UNDEFINED" => Some(Self::Undefined),
+            "JSW_UNSPEC" => Some(Self::JswUnspec),
+            "JSW_NONE" => Some(Self::JswNone),
+            "JSW_CONDITIONAL" => Some(Self::JswConditional),
+            "JSW_UNCONDITIONAL" => Some(Self::JswUnconditional),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonBehaviorType {
+    Undefined = 0,
+    JsonBehaviorNull = 1,
+    JsonBehaviorError = 2,
+    JsonBehaviorEmpty = 3,
+    JsonBehaviorTrue = 4,
+    JsonBehaviorFalse = 5,
+    JsonBehaviorUnknown = 6,
+    JsonBehaviorEmptyArray = 7,
+    JsonBehaviorEmptyObject = 8,
+    JsonBehaviorDefault = 9,
+}
+impl JsonBehaviorType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_BEHAVIOR_TYPE_UNDEFINED",
+            Self::JsonBehaviorNull => "JSON_BEHAVIOR_NULL",
+            Self::JsonBehaviorError => "JSON_BEHAVIOR_ERROR",
+            Self::JsonBehaviorEmpty => "JSON_BEHAVIOR_EMPTY",
+            Self::JsonBehaviorTrue => "JSON_BEHAVIOR_TRUE",
+            Self::JsonBehaviorFalse => "JSON_BEHAVIOR_FALSE",
+            Self::JsonBehaviorUnknown => "JSON_BEHAVIOR_UNKNOWN",
+            Self::JsonBehaviorEmptyArray => "JSON_BEHAVIOR_EMPTY_ARRAY",
+            Self::JsonBehaviorEmptyObject => "JSON_BEHAVIOR_EMPTY_OBJECT",
+            Self::JsonBehaviorDefault => "JSON_BEHAVIOR_DEFAULT",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_BEHAVIOR_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "JSON_BEHAVIOR_NULL" => Some(Self::JsonBehaviorNull),
+            "JSON_BEHAVIOR_ERROR" => Some(Self::JsonBehaviorError),
+            "JSON_BEHAVIOR_EMPTY" => Some(Self::JsonBehaviorEmpty),
+            "JSON_BEHAVIOR_TRUE" => Some(Self::JsonBehaviorTrue),
+            "JSON_BEHAVIOR_FALSE" => Some(Self::JsonBehaviorFalse),
+            "JSON_BEHAVIOR_UNKNOWN" => Some(Self::JsonBehaviorUnknown),
+            "JSON_BEHAVIOR_EMPTY_ARRAY" => Some(Self::JsonBehaviorEmptyArray),
+            "JSON_BEHAVIOR_EMPTY_OBJECT" => Some(Self::JsonBehaviorEmptyObject),
+            "JSON_BEHAVIOR_DEFAULT" => Some(Self::JsonBehaviorDefault),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JsonExprOp {
+    Undefined = 0,
+    JsonExistsOp = 1,
+    JsonQueryOp = 2,
+    JsonValueOp = 3,
+    JsonTableOp = 4,
+}
+impl JsonExprOp {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JSON_EXPR_OP_UNDEFINED",
+            Self::JsonExistsOp => "JSON_EXISTS_OP",
+            Self::JsonQueryOp => "JSON_QUERY_OP",
+            Self::JsonValueOp => "JSON_VALUE_OP",
+            Self::JsonTableOp => "JSON_TABLE_OP",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JSON_EXPR_OP_UNDEFINED" => Some(Self::Undefined),
+            "JSON_EXISTS_OP" => Some(Self::JsonExistsOp),
+            "JSON_QUERY_OP" => Some(Self::JsonQueryOp),
+            "JSON_VALUE_OP" => Some(Self::JsonValueOp),
+            "JSON_TABLE_OP" => Some(Self::JsonTableOp),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum NullTestType {
+    Undefined = 0,
+    IsNull = 1,
+    IsNotNull = 2,
+}
+impl NullTestType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "NULL_TEST_TYPE_UNDEFINED",
+            Self::IsNull => "IS_NULL",
+            Self::IsNotNull => "IS_NOT_NULL",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "NULL_TEST_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "IS_NULL" => Some(Self::IsNull),
+            "IS_NOT_NULL" => Some(Self::IsNotNull),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum BoolTestType {
+    Undefined = 0,
+    IsTrue = 1,
+    IsNotTrue = 2,
+    IsFalse = 3,
+    IsNotFalse = 4,
+    IsUnknown = 5,
+    IsNotUnknown = 6,
+}
+impl BoolTestType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "BOOL_TEST_TYPE_UNDEFINED",
+            Self::IsTrue => "IS_TRUE",
+            Self::IsNotTrue => "IS_NOT_TRUE",
+            Self::IsFalse => "IS_FALSE",
+            Self::IsNotFalse => "IS_NOT_FALSE",
+            Self::IsUnknown => "IS_UNKNOWN",
+            Self::IsNotUnknown => "IS_NOT_UNKNOWN",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "BOOL_TEST_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "IS_TRUE" => Some(Self::IsTrue),
+            "IS_NOT_TRUE" => Some(Self::IsNotTrue),
+            "IS_FALSE" => Some(Self::IsFalse),
+            "IS_NOT_FALSE" => Some(Self::IsNotFalse),
+            "IS_UNKNOWN" => Some(Self::IsUnknown),
+            "IS_NOT_UNKNOWN" => Some(Self::IsNotUnknown),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum MergeMatchKind {
+    Undefined = 0,
+    MergeWhenMatched = 1,
+    MergeWhenNotMatchedBySource = 2,
+    MergeWhenNotMatchedByTarget = 3,
+}
+impl MergeMatchKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "MERGE_MATCH_KIND_UNDEFINED",
+            Self::MergeWhenMatched => "MERGE_WHEN_MATCHED",
+            Self::MergeWhenNotMatchedBySource => "MERGE_WHEN_NOT_MATCHED_BY_SOURCE",
+            Self::MergeWhenNotMatchedByTarget => "MERGE_WHEN_NOT_MATCHED_BY_TARGET",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "MERGE_MATCH_KIND_UNDEFINED" => Some(Self::Undefined),
+            "MERGE_WHEN_MATCHED" => Some(Self::MergeWhenMatched),
+            "MERGE_WHEN_NOT_MATCHED_BY_SOURCE" => Some(Self::MergeWhenNotMatchedBySource),
+            "MERGE_WHEN_NOT_MATCHED_BY_TARGET" => Some(Self::MergeWhenNotMatchedByTarget),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum CmdType {
+    Undefined = 0,
+    CmdUnknown = 1,
+    CmdSelect = 2,
+    CmdUpdate = 3,
+    CmdInsert = 4,
+    CmdDelete = 5,
+    CmdMerge = 6,
+    CmdUtility = 7,
+    CmdNothing = 8,
+}
+impl CmdType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "CMD_TYPE_UNDEFINED",
+            Self::CmdUnknown => "CMD_UNKNOWN",
+            Self::CmdSelect => "CMD_SELECT",
+            Self::CmdUpdate => "CMD_UPDATE",
+            Self::CmdInsert => "CMD_INSERT",
+            Self::CmdDelete => "CMD_DELETE",
+            Self::CmdMerge => "CMD_MERGE",
+            Self::CmdUtility => "CMD_UTILITY",
+            Self::CmdNothing => "CMD_NOTHING",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "CMD_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "CMD_UNKNOWN" => Some(Self::CmdUnknown),
+            "CMD_SELECT" => Some(Self::CmdSelect),
+            "CMD_UPDATE" => Some(Self::CmdUpdate),
+            "CMD_INSERT" => Some(Self::CmdInsert),
+            "CMD_DELETE" => Some(Self::CmdDelete),
+            "CMD_MERGE" => Some(Self::CmdMerge),
+            "CMD_UTILITY" => Some(Self::CmdUtility),
+            "CMD_NOTHING" => Some(Self::CmdNothing),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum JoinType {
+    Undefined = 0,
+    JoinInner = 1,
+    JoinLeft = 2,
+    JoinFull = 3,
+    JoinRight = 4,
+    JoinSemi = 5,
+    JoinAnti = 6,
+    JoinRightAnti = 7,
+    JoinUniqueOuter = 8,
+    JoinUniqueInner = 9,
+}
+impl JoinType {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "JOIN_TYPE_UNDEFINED",
+            Self::JoinInner => "JOIN_INNER",
+            Self::JoinLeft => "JOIN_LEFT",
+            Self::JoinFull => "JOIN_FULL",
+            Self::JoinRight => "JOIN_RIGHT",
+            Self::JoinSemi => "JOIN_SEMI",
+            Self::JoinAnti => "JOIN_ANTI",
+            Self::JoinRightAnti => "JOIN_RIGHT_ANTI",
+            Self::JoinUniqueOuter => "JOIN_UNIQUE_OUTER",
+            Self::JoinUniqueInner => "JOIN_UNIQUE_INNER",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "JOIN_TYPE_UNDEFINED" => Some(Self::Undefined),
+            "JOIN_INNER" => Some(Self::JoinInner),
+            "JOIN_LEFT" => Some(Self::JoinLeft),
+            "JOIN_FULL" => Some(Self::JoinFull),
+            "JOIN_RIGHT" => Some(Self::JoinRight),
+            "JOIN_SEMI" => Some(Self::JoinSemi),
+            "JOIN_ANTI" => Some(Self::JoinAnti),
+            "JOIN_RIGHT_ANTI" => Some(Self::JoinRightAnti),
+            "JOIN_UNIQUE_OUTER" => Some(Self::JoinUniqueOuter),
+            "JOIN_UNIQUE_INNER" => Some(Self::JoinUniqueInner),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum AggStrategy {
+    Undefined = 0,
+    AggPlain = 1,
+    AggSorted = 2,
+    AggHashed = 3,
+    AggMixed = 4,
+}
+impl AggStrategy {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "AGG_STRATEGY_UNDEFINED",
+            Self::AggPlain => "AGG_PLAIN",
+            Self::AggSorted => "AGG_SORTED",
+            Self::AggHashed => "AGG_HASHED",
+            Self::AggMixed => "AGG_MIXED",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "AGG_STRATEGY_UNDEFINED" => Some(Self::Undefined),
+            "AGG_PLAIN" => Some(Self::AggPlain),
+            "AGG_SORTED" => Some(Self::AggSorted),
+            "AGG_HASHED" => Some(Self::AggHashed),
+            "AGG_MIXED" => Some(Self::AggMixed),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum AggSplit {
+    Undefined = 0,
+    AggsplitSimple = 1,
+    AggsplitInitialSerial = 2,
+    AggsplitFinalDeserial = 3,
+}
+impl AggSplit {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "AGG_SPLIT_UNDEFINED",
+            Self::AggsplitSimple => "AGGSPLIT_SIMPLE",
+            Self::AggsplitInitialSerial => "AGGSPLIT_INITIAL_SERIAL",
+            Self::AggsplitFinalDeserial => "AGGSPLIT_FINAL_DESERIAL",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "AGG_SPLIT_UNDEFINED" => Some(Self::Undefined),
+            "AGGSPLIT_SIMPLE" => Some(Self::AggsplitSimple),
+            "AGGSPLIT_INITIAL_SERIAL" => Some(Self::AggsplitInitialSerial),
+            "AGGSPLIT_FINAL_DESERIAL" => Some(Self::AggsplitFinalDeserial),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum SetOpCmd {
+    Undefined = 0,
+    SetopcmdIntersect = 1,
+    SetopcmdIntersectAll = 2,
+    SetopcmdExcept = 3,
+    SetopcmdExceptAll = 4,
+}
+impl SetOpCmd {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "SET_OP_CMD_UNDEFINED",
+            Self::SetopcmdIntersect => "SETOPCMD_INTERSECT",
+            Self::SetopcmdIntersectAll => "SETOPCMD_INTERSECT_ALL",
+            Self::SetopcmdExcept => "SETOPCMD_EXCEPT",
+            Self::SetopcmdExceptAll => "SETOPCMD_EXCEPT_ALL",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "SET_OP_CMD_UNDEFINED" => Some(Self::Undefined),
+            "SETOPCMD_INTERSECT" => Some(Self::SetopcmdIntersect),
+            "SETOPCMD_INTERSECT_ALL" => Some(Self::SetopcmdIntersectAll),
+            "SETOPCMD_EXCEPT" => Some(Self::SetopcmdExcept),
+            "SETOPCMD_EXCEPT_ALL" => Some(Self::SetopcmdExceptAll),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum SetOpStrategy {
+    Undefined = 0,
+    SetopSorted = 1,
+    SetopHashed = 2,
+}
+impl SetOpStrategy {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "SET_OP_STRATEGY_UNDEFINED",
+            Self::SetopSorted => "SETOP_SORTED",
+            Self::SetopHashed => "SETOP_HASHED",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "SET_OP_STRATEGY_UNDEFINED" => Some(Self::Undefined),
+            "SETOP_SORTED" => Some(Self::SetopSorted),
+            "SETOP_HASHED" => Some(Self::SetopHashed),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum OnConflictAction {
+    Undefined = 0,
+    OnconflictNone = 1,
+    OnconflictNothing = 2,
+    OnconflictUpdate = 3,
+}
+impl OnConflictAction {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "ON_CONFLICT_ACTION_UNDEFINED",
+            Self::OnconflictNone => "ONCONFLICT_NONE",
+            Self::OnconflictNothing => "ONCONFLICT_NOTHING",
+            Self::OnconflictUpdate => "ONCONFLICT_UPDATE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "ON_CONFLICT_ACTION_UNDEFINED" => Some(Self::Undefined),
+            "ONCONFLICT_NONE" => Some(Self::OnconflictNone),
+            "ONCONFLICT_NOTHING" => Some(Self::OnconflictNothing),
+            "ONCONFLICT_UPDATE" => Some(Self::OnconflictUpdate),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum LimitOption {
+    Undefined = 0,
+    Default = 1,
+    Count = 2,
+    WithTies = 3,
+}
+impl LimitOption {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "LIMIT_OPTION_UNDEFINED",
+            Self::Default => "LIMIT_OPTION_DEFAULT",
+            Self::Count => "LIMIT_OPTION_COUNT",
+            Self::WithTies => "LIMIT_OPTION_WITH_TIES",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "LIMIT_OPTION_UNDEFINED" => Some(Self::Undefined),
+            "LIMIT_OPTION_DEFAULT" => Some(Self::Default),
+            "LIMIT_OPTION_COUNT" => Some(Self::Count),
+            "LIMIT_OPTION_WITH_TIES" => Some(Self::WithTies),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum LockClauseStrength {
+    Undefined = 0,
+    LcsNone = 1,
+    LcsForkeyshare = 2,
+    LcsForshare = 3,
+    LcsFornokeyupdate = 4,
+    LcsForupdate = 5,
+}
+impl LockClauseStrength {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "LOCK_CLAUSE_STRENGTH_UNDEFINED",
+            Self::LcsNone => "LCS_NONE",
+            Self::LcsForkeyshare => "LCS_FORKEYSHARE",
+            Self::LcsForshare => "LCS_FORSHARE",
+            Self::LcsFornokeyupdate => "LCS_FORNOKEYUPDATE",
+            Self::LcsForupdate => "LCS_FORUPDATE",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "LOCK_CLAUSE_STRENGTH_UNDEFINED" => Some(Self::Undefined),
+            "LCS_NONE" => Some(Self::LcsNone),
+            "LCS_FORKEYSHARE" => Some(Self::LcsForkeyshare),
+            "LCS_FORSHARE" => Some(Self::LcsForshare),
+            "LCS_FORNOKEYUPDATE" => Some(Self::LcsFornokeyupdate),
+            "LCS_FORUPDATE" => Some(Self::LcsForupdate),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum LockWaitPolicy {
+    Undefined = 0,
+    LockWaitBlock = 1,
+    LockWaitSkip = 2,
+    LockWaitError = 3,
+}
+impl LockWaitPolicy {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "LOCK_WAIT_POLICY_UNDEFINED",
+            Self::LockWaitBlock => "LockWaitBlock",
+            Self::LockWaitSkip => "LockWaitSkip",
+            Self::LockWaitError => "LockWaitError",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "LOCK_WAIT_POLICY_UNDEFINED" => Some(Self::Undefined),
+            "LockWaitBlock" => Some(Self::LockWaitBlock),
+            "LockWaitSkip" => Some(Self::LockWaitSkip),
+            "LockWaitError" => Some(Self::LockWaitError),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum LockTupleMode {
+    Undefined = 0,
+    LockTupleKeyShare = 1,
+    LockTupleShare = 2,
+    LockTupleNoKeyExclusive = 3,
+    LockTupleExclusive = 4,
+}
+impl LockTupleMode {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Undefined => "LOCK_TUPLE_MODE_UNDEFINED",
+            Self::LockTupleKeyShare => "LockTupleKeyShare",
+            Self::LockTupleShare => "LockTupleShare",
+            Self::LockTupleNoKeyExclusive => "LockTupleNoKeyExclusive",
+            Self::LockTupleExclusive => "LockTupleExclusive",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "LOCK_TUPLE_MODE_UNDEFINED" => Some(Self::Undefined),
+            "LockTupleKeyShare" => Some(Self::LockTupleKeyShare),
+            "LockTupleShare" => Some(Self::LockTupleShare),
+            "LockTupleNoKeyExclusive" => Some(Self::LockTupleNoKeyExclusive),
+            "LockTupleExclusive" => Some(Self::LockTupleExclusive),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum KeywordKind {
+    NoKeyword = 0,
+    UnreservedKeyword = 1,
+    ColNameKeyword = 2,
+    TypeFuncNameKeyword = 3,
+    ReservedKeyword = 4,
+}
+impl KeywordKind {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::NoKeyword => "NO_KEYWORD",
+            Self::UnreservedKeyword => "UNRESERVED_KEYWORD",
+            Self::ColNameKeyword => "COL_NAME_KEYWORD",
+            Self::TypeFuncNameKeyword => "TYPE_FUNC_NAME_KEYWORD",
+            Self::ReservedKeyword => "RESERVED_KEYWORD",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "NO_KEYWORD" => Some(Self::NoKeyword),
+            "UNRESERVED_KEYWORD" => Some(Self::UnreservedKeyword),
+            "COL_NAME_KEYWORD" => Some(Self::ColNameKeyword),
+            "TYPE_FUNC_NAME_KEYWORD" => Some(Self::TypeFuncNameKeyword),
+            "RESERVED_KEYWORD" => Some(Self::ReservedKeyword),
+            _ => None,
+        }
+    }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum Token {
+    Nul = 0,
+    /// Single-character tokens that are returned 1:1 (identical with "self" list in scan.l)
+    /// Either supporting syntax, or single-character operators (some can be both)
+    /// Also see <https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-SYNTAX-SPECIAL-CHARS>
+    ///
+    /// "$"
+    Ascii36 = 36,
+    /// "%"
+    Ascii37 = 37,
+    /// "("
+    Ascii40 = 40,
+    /// ")"
+    Ascii41 = 41,
+    /// "*"
+    Ascii42 = 42,
+    /// "+"
+    Ascii43 = 43,
+    /// ","
+    Ascii44 = 44,
+    /// "-"
+    Ascii45 = 45,
+    /// "."
+    Ascii46 = 46,
+    /// "/"
+    Ascii47 = 47,
+    /// ":"
+    Ascii58 = 58,
+    /// ";"
+    Ascii59 = 59,
+    /// "<"
+    Ascii60 = 60,
+    /// "="
+    Ascii61 = 61,
+    /// ">"
+    Ascii62 = 62,
+    /// "?"
+    Ascii63 = 63,
+    /// "["
+    Ascii91 = 91,
+    /// "\"
+    Ascii92 = 92,
+    /// "]"
+    Ascii93 = 93,
+    /// "^"
+    Ascii94 = 94,
+    /// Named tokens in scan.l
+    Ident = 258,
+    Uident = 259,
+    Fconst = 260,
+    Sconst = 261,
+    Usconst = 262,
+    Bconst = 263,
+    Xconst = 264,
+    Op = 265,
+    Iconst = 266,
+    Param = 267,
+    Typecast = 268,
+    DotDot = 269,
+    ColonEquals = 270,
+    EqualsGreater = 271,
+    LessEquals = 272,
+    GreaterEquals = 273,
+    NotEquals = 274,
+    SqlComment = 275,
+    CComment = 276,
+    AbortP = 277,
+    Absent = 278,
+    AbsoluteP = 279,
+    Access = 280,
+    Action = 281,
+    AddP = 282,
+    Admin = 283,
+    After = 284,
+    Aggregate = 285,
+    All = 286,
+    Also = 287,
+    Alter = 288,
+    Always = 289,
+    Analyse = 290,
+    Analyze = 291,
+    And = 292,
+    Any = 293,
+    Array = 294,
+    As = 295,
+    Asc = 296,
+    Asensitive = 297,
+    Assertion = 298,
+    Assignment = 299,
+    Asymmetric = 300,
+    Atomic = 301,
+    At = 302,
+    Attach = 303,
+    Attribute = 304,
+    Authorization = 305,
+    Backward = 306,
+    Before = 307,
+    BeginP = 308,
+    Between = 309,
+    Bigint = 310,
+    Binary = 311,
+    Bit = 312,
+    BooleanP = 313,
+    Both = 314,
+    Breadth = 315,
+    By = 316,
+    Cache = 317,
+    Call = 318,
+    Called = 319,
+    Cascade = 320,
+    Cascaded = 321,
+    Case = 322,
+    Cast = 323,
+    CatalogP = 324,
+    Chain = 325,
+    CharP = 326,
+    Character = 327,
+    Characteristics = 328,
+    Check = 329,
+    Checkpoint = 330,
+    Class = 331,
+    Close = 332,
+    Cluster = 333,
+    Coalesce = 334,
+    Collate = 335,
+    Collation = 336,
+    Column = 337,
+    Columns = 338,
+    Comment = 339,
+    Comments = 340,
+    Commit = 341,
+    Committed = 342,
+    Compression = 343,
+    Concurrently = 344,
+    Conditional = 345,
+    Configuration = 346,
+    Conflict = 347,
+    Connection = 348,
+    Constraint = 349,
+    Constraints = 350,
+    ContentP = 351,
+    ContinueP = 352,
+    ConversionP = 353,
+    Copy = 354,
+    Cost = 355,
+    Create = 356,
+    Cross = 357,
+    Csv = 358,
+    Cube = 359,
+    CurrentP = 360,
+    CurrentCatalog = 361,
+    CurrentDate = 362,
+    CurrentRole = 363,
+    CurrentSchema = 364,
+    CurrentTime = 365,
+    CurrentTimestamp = 366,
+    CurrentUser = 367,
+    Cursor = 368,
+    Cycle = 369,
+    DataP = 370,
+    Database = 371,
+    DayP = 372,
+    Deallocate = 373,
+    Dec = 374,
+    DecimalP = 375,
+    Declare = 376,
+    Default = 377,
+    Defaults = 378,
+    Deferrable = 379,
+    Deferred = 380,
+    Definer = 381,
+    DeleteP = 382,
+    Delimiter = 383,
+    Delimiters = 384,
+    Depends = 385,
+    Depth = 386,
+    Desc = 387,
+    Detach = 388,
+    Dictionary = 389,
+    DisableP = 390,
+    Discard = 391,
+    Distinct = 392,
+    Do = 393,
+    DocumentP = 394,
+    DomainP = 395,
+    DoubleP = 396,
+    Drop = 397,
+    Each = 398,
+    Else = 399,
+    EmptyP = 400,
+    EnableP = 401,
+    Encoding = 402,
+    Encrypted = 403,
+    EndP = 404,
+    EnumP = 405,
+    ErrorP = 406,
+    Escape = 407,
+    Event = 408,
+    Except = 409,
+    Exclude = 410,
+    Excluding = 411,
+    Exclusive = 412,
+    Execute = 413,
+    Exists = 414,
+    Explain = 415,
+    Expression = 416,
+    Extension = 417,
+    External = 418,
+    Extract = 419,
+    FalseP = 420,
+    Family = 421,
+    Fetch = 422,
+    Filter = 423,
+    Finalize = 424,
+    FirstP = 425,
+    FloatP = 426,
+    Following = 427,
+    For = 428,
+    Force = 429,
+    Foreign = 430,
+    Format = 431,
+    Forward = 432,
+    Freeze = 433,
+    From = 434,
+    Full = 435,
+    Function = 436,
+    Functions = 437,
+    Generated = 438,
+    Global = 439,
+    Grant = 440,
+    Granted = 441,
+    Greatest = 442,
+    GroupP = 443,
+    Grouping = 444,
+    Groups = 445,
+    Handler = 446,
+    Having = 447,
+    HeaderP = 448,
+    Hold = 449,
+    HourP = 450,
+    IdentityP = 451,
+    IfP = 452,
+    Ilike = 453,
+    Immediate = 454,
+    Immutable = 455,
+    ImplicitP = 456,
+    ImportP = 457,
+    InP = 458,
+    Include = 459,
+    Including = 460,
+    Increment = 461,
+    Indent = 462,
+    Index = 463,
+    Indexes = 464,
+    Inherit = 465,
+    Inherits = 466,
+    Initially = 467,
+    InlineP = 468,
+    InnerP = 469,
+    Inout = 470,
+    InputP = 471,
+    Insensitive = 472,
+    Insert = 473,
+    Instead = 474,
+    IntP = 475,
+    Integer = 476,
+    Intersect = 477,
+    Interval = 478,
+    Into = 479,
+    Invoker = 480,
+    Is = 481,
+    Isnull = 482,
+    Isolation = 483,
+    Join = 484,
+    Json = 485,
+    JsonArray = 486,
+    JsonArrayagg = 487,
+    JsonExists = 488,
+    JsonObject = 489,
+    JsonObjectagg = 490,
+    JsonQuery = 491,
+    JsonScalar = 492,
+    JsonSerialize = 493,
+    JsonTable = 494,
+    JsonValue = 495,
+    Keep = 496,
+    Key = 497,
+    Keys = 498,
+    Label = 499,
+    Language = 500,
+    LargeP = 501,
+    LastP = 502,
+    LateralP = 503,
+    Leading = 504,
+    Leakproof = 505,
+    Least = 506,
+    Left = 507,
+    Level = 508,
+    Like = 509,
+    Limit = 510,
+    Listen = 511,
+    Load = 512,
+    Local = 513,
+    Localtime = 514,
+    Localtimestamp = 515,
+    Location = 516,
+    LockP = 517,
+    Locked = 518,
+    Logged = 519,
+    Mapping = 520,
+    Match = 521,
+    Matched = 522,
+    Materialized = 523,
+    Maxvalue = 524,
+    Merge = 525,
+    MergeAction = 526,
+    Method = 527,
+    MinuteP = 528,
+    Minvalue = 529,
+    Mode = 530,
+    MonthP = 531,
+    Move = 532,
+    NameP = 533,
+    Names = 534,
+    National = 535,
+    Natural = 536,
+    Nchar = 537,
+    Nested = 538,
+    New = 539,
+    Next = 540,
+    Nfc = 541,
+    Nfd = 542,
+    Nfkc = 543,
+    Nfkd = 544,
+    No = 545,
+    None = 546,
+    Normalize = 547,
+    Normalized = 548,
+    Not = 549,
+    Nothing = 550,
+    Notify = 551,
+    Notnull = 552,
+    Nowait = 553,
+    NullP = 554,
+    Nullif = 555,
+    NullsP = 556,
+    Numeric = 557,
+    ObjectP = 558,
+    Of = 559,
+    Off = 560,
+    Offset = 561,
+    Oids = 562,
+    Old = 563,
+    Omit = 564,
+    On = 565,
+    Only = 566,
+    Operator = 567,
+    Option = 568,
+    Options = 569,
+    Or = 570,
+    Order = 571,
+    Ordinality = 572,
+    Others = 573,
+    OutP = 574,
+    OuterP = 575,
+    Over = 576,
+    Overlaps = 577,
+    Overlay = 578,
+    Overriding = 579,
+    Owned = 580,
+    Owner = 581,
+    Parallel = 582,
+    Parameter = 583,
+    Parser = 584,
+    Partial = 585,
+    Partition = 586,
+    Passing = 587,
+    Password = 588,
+    Path = 589,
+    Placing = 590,
+    Plan = 591,
+    Plans = 592,
+    Policy = 593,
+    Position = 594,
+    Preceding = 595,
+    Precision = 596,
+    Preserve = 597,
+    Prepare = 598,
+    Prepared = 599,
+    Primary = 600,
+    Prior = 601,
+    Privileges = 602,
+    Procedural = 603,
+    Procedure = 604,
+    Procedures = 605,
+    Program = 606,
+    Publication = 607,
+    Quote = 608,
+    Quotes = 609,
+    Range = 610,
+    Read = 611,
+    Real = 612,
+    Reassign = 613,
+    Recheck = 614,
+    Recursive = 615,
+    RefP = 616,
+    References = 617,
+    Referencing = 618,
+    Refresh = 619,
+    Reindex = 620,
+    RelativeP = 621,
+    Release = 622,
+    Rename = 623,
+    Repeatable = 624,
+    Replace = 625,
+    Replica = 626,
+    Reset = 627,
+    Restart = 628,
+    Restrict = 629,
+    Return = 630,
+    Returning = 631,
+    Returns = 632,
+    Revoke = 633,
+    Right = 634,
+    Role = 635,
+    Rollback = 636,
+    Rollup = 637,
+    Routine = 638,
+    Routines = 639,
+    Row = 640,
+    Rows = 641,
+    Rule = 642,
+    Savepoint = 643,
+    Scalar = 644,
+    Schema = 645,
+    Schemas = 646,
+    Scroll = 647,
+    Search = 648,
+    SecondP = 649,
+    Security = 650,
+    Select = 651,
+    Sequence = 652,
+    Sequences = 653,
+    Serializable = 654,
+    Server = 655,
+    Session = 656,
+    SessionUser = 657,
+    Set = 658,
+    Sets = 659,
+    Setof = 660,
+    Share = 661,
+    Show = 662,
+    Similar = 663,
+    Simple = 664,
+    Skip = 665,
+    Smallint = 666,
+    Snapshot = 667,
+    Some = 668,
+    Source = 669,
+    SqlP = 670,
+    Stable = 671,
+    StandaloneP = 672,
+    Start = 673,
+    Statement = 674,
+    Statistics = 675,
+    Stdin = 676,
+    Stdout = 677,
+    Storage = 678,
+    Stored = 679,
+    StrictP = 680,
+    StringP = 681,
+    StripP = 682,
+    Subscription = 683,
+    Substring = 684,
+    Support = 685,
+    Symmetric = 686,
+    Sysid = 687,
+    SystemP = 688,
+    SystemUser = 689,
+    Table = 690,
+    Tables = 691,
+    Tablesample = 692,
+    Tablespace = 693,
+    Target = 694,
+    Temp = 695,
+    Template = 696,
+    Temporary = 697,
+    TextP = 698,
+    Then = 699,
+    Ties = 700,
+    Time = 701,
+    Timestamp = 702,
+    To = 703,
+    Trailing = 704,
+    Transaction = 705,
+    Transform = 706,
+    Treat = 707,
+    Trigger = 708,
+    Trim = 709,
+    TrueP = 710,
+    Truncate = 711,
+    Trusted = 712,
+    TypeP = 713,
+    TypesP = 714,
+    Uescape = 715,
+    Unbounded = 716,
+    Unconditional = 717,
+    Uncommitted = 718,
+    Unencrypted = 719,
+    Union = 720,
+    Unique = 721,
+    Unknown = 722,
+    Unlisten = 723,
+    Unlogged = 724,
+    Until = 725,
+    Update = 726,
+    User = 727,
+    Using = 728,
+    Vacuum = 729,
+    Valid = 730,
+    Validate = 731,
+    Validator = 732,
+    ValueP = 733,
+    Values = 734,
+    Varchar = 735,
+    Variadic = 736,
+    Varying = 737,
+    Verbose = 738,
+    VersionP = 739,
+    View = 740,
+    Views = 741,
+    Volatile = 742,
+    When = 743,
+    Where = 744,
+    WhitespaceP = 745,
+    Window = 746,
+    With = 747,
+    Within = 748,
+    Without = 749,
+    Work = 750,
+    Wrapper = 751,
+    Write = 752,
+    XmlP = 753,
+    Xmlattributes = 754,
+    Xmlconcat = 755,
+    Xmlelement = 756,
+    Xmlexists = 757,
+    Xmlforest = 758,
+    Xmlnamespaces = 759,
+    Xmlparse = 760,
+    Xmlpi = 761,
+    Xmlroot = 762,
+    Xmlserialize = 763,
+    Xmltable = 764,
+    YearP = 765,
+    YesP = 766,
+    Zone = 767,
+    FormatLa = 768,
+    NotLa = 769,
+    NullsLa = 770,
+    WithLa = 771,
+    WithoutLa = 772,
+    ModeTypeName = 773,
+    ModePlpgsqlExpr = 774,
+    ModePlpgsqlAssign1 = 775,
+    ModePlpgsqlAssign2 = 776,
+    ModePlpgsqlAssign3 = 777,
+    Uminus = 778,
+}
+impl Token {
+    /// String value of the enum field names used in the ProtoBuf definition.
+    ///
+    /// The values are not transformed in any way and thus are considered stable
+    /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+    pub fn as_str_name(&self) -> &'static str {
+        match self {
+            Self::Nul => "NUL",
+            Self::Ascii36 => "ASCII_36",
+            Self::Ascii37 => "ASCII_37",
+            Self::Ascii40 => "ASCII_40",
+            Self::Ascii41 => "ASCII_41",
+            Self::Ascii42 => "ASCII_42",
+            Self::Ascii43 => "ASCII_43",
+            Self::Ascii44 => "ASCII_44",
+            Self::Ascii45 => "ASCII_45",
+            Self::Ascii46 => "ASCII_46",
+            Self::Ascii47 => "ASCII_47",
+            Self::Ascii58 => "ASCII_58",
+            Self::Ascii59 => "ASCII_59",
+            Self::Ascii60 => "ASCII_60",
+            Self::Ascii61 => "ASCII_61",
+            Self::Ascii62 => "ASCII_62",
+            Self::Ascii63 => "ASCII_63",
+            Self::Ascii91 => "ASCII_91",
+            Self::Ascii92 => "ASCII_92",
+            Self::Ascii93 => "ASCII_93",
+            Self::Ascii94 => "ASCII_94",
+            Self::Ident => "IDENT",
+            Self::Uident => "UIDENT",
+            Self::Fconst => "FCONST",
+            Self::Sconst => "SCONST",
+            Self::Usconst => "USCONST",
+            Self::Bconst => "BCONST",
+            Self::Xconst => "XCONST",
+            Self::Op => "Op",
+            Self::Iconst => "ICONST",
+            Self::Param => "PARAM",
+            Self::Typecast => "TYPECAST",
+            Self::DotDot => "DOT_DOT",
+            Self::ColonEquals => "COLON_EQUALS",
+            Self::EqualsGreater => "EQUALS_GREATER",
+            Self::LessEquals => "LESS_EQUALS",
+            Self::GreaterEquals => "GREATER_EQUALS",
+            Self::NotEquals => "NOT_EQUALS",
+            Self::SqlComment => "SQL_COMMENT",
+            Self::CComment => "C_COMMENT",
+            Self::AbortP => "ABORT_P",
+            Self::Absent => "ABSENT",
+            Self::AbsoluteP => "ABSOLUTE_P",
+            Self::Access => "ACCESS",
+            Self::Action => "ACTION",
+            Self::AddP => "ADD_P",
+            Self::Admin => "ADMIN",
+            Self::After => "AFTER",
+            Self::Aggregate => "AGGREGATE",
+            Self::All => "ALL",
+            Self::Also => "ALSO",
+            Self::Alter => "ALTER",
+            Self::Always => "ALWAYS",
+            Self::Analyse => "ANALYSE",
+            Self::Analyze => "ANALYZE",
+            Self::And => "AND",
+            Self::Any => "ANY",
+            Self::Array => "ARRAY",
+            Self::As => "AS",
+            Self::Asc => "ASC",
+            Self::Asensitive => "ASENSITIVE",
+            Self::Assertion => "ASSERTION",
+            Self::Assignment => "ASSIGNMENT",
+            Self::Asymmetric => "ASYMMETRIC",
+            Self::Atomic => "ATOMIC",
+            Self::At => "AT",
+            Self::Attach => "ATTACH",
+            Self::Attribute => "ATTRIBUTE",
+            Self::Authorization => "AUTHORIZATION",
+            Self::Backward => "BACKWARD",
+            Self::Before => "BEFORE",
+            Self::BeginP => "BEGIN_P",
+            Self::Between => "BETWEEN",
+            Self::Bigint => "BIGINT",
+            Self::Binary => "BINARY",
+            Self::Bit => "BIT",
+            Self::BooleanP => "BOOLEAN_P",
+            Self::Both => "BOTH",
+            Self::Breadth => "BREADTH",
+            Self::By => "BY",
+            Self::Cache => "CACHE",
+            Self::Call => "CALL",
+            Self::Called => "CALLED",
+            Self::Cascade => "CASCADE",
+            Self::Cascaded => "CASCADED",
+            Self::Case => "CASE",
+            Self::Cast => "CAST",
+            Self::CatalogP => "CATALOG_P",
+            Self::Chain => "CHAIN",
+            Self::CharP => "CHAR_P",
+            Self::Character => "CHARACTER",
+            Self::Characteristics => "CHARACTERISTICS",
+            Self::Check => "CHECK",
+            Self::Checkpoint => "CHECKPOINT",
+            Self::Class => "CLASS",
+            Self::Close => "CLOSE",
+            Self::Cluster => "CLUSTER",
+            Self::Coalesce => "COALESCE",
+            Self::Collate => "COLLATE",
+            Self::Collation => "COLLATION",
+            Self::Column => "COLUMN",
+            Self::Columns => "COLUMNS",
+            Self::Comment => "COMMENT",
+            Self::Comments => "COMMENTS",
+            Self::Commit => "COMMIT",
+            Self::Committed => "COMMITTED",
+            Self::Compression => "COMPRESSION",
+            Self::Concurrently => "CONCURRENTLY",
+            Self::Conditional => "CONDITIONAL",
+            Self::Configuration => "CONFIGURATION",
+            Self::Conflict => "CONFLICT",
+            Self::Connection => "CONNECTION",
+            Self::Constraint => "CONSTRAINT",
+            Self::Constraints => "CONSTRAINTS",
+            Self::ContentP => "CONTENT_P",
+            Self::ContinueP => "CONTINUE_P",
+            Self::ConversionP => "CONVERSION_P",
+            Self::Copy => "COPY",
+            Self::Cost => "COST",
+            Self::Create => "CREATE",
+            Self::Cross => "CROSS",
+            Self::Csv => "CSV",
+            Self::Cube => "CUBE",
+            Self::CurrentP => "CURRENT_P",
+            Self::CurrentCatalog => "CURRENT_CATALOG",
+            Self::CurrentDate => "CURRENT_DATE",
+            Self::CurrentRole => "CURRENT_ROLE",
+            Self::CurrentSchema => "CURRENT_SCHEMA",
+            Self::CurrentTime => "CURRENT_TIME",
+            Self::CurrentTimestamp => "CURRENT_TIMESTAMP",
+            Self::CurrentUser => "CURRENT_USER",
+            Self::Cursor => "CURSOR",
+            Self::Cycle => "CYCLE",
+            Self::DataP => "DATA_P",
+            Self::Database => "DATABASE",
+            Self::DayP => "DAY_P",
+            Self::Deallocate => "DEALLOCATE",
+            Self::Dec => "DEC",
+            Self::DecimalP => "DECIMAL_P",
+            Self::Declare => "DECLARE",
+            Self::Default => "DEFAULT",
+            Self::Defaults => "DEFAULTS",
+            Self::Deferrable => "DEFERRABLE",
+            Self::Deferred => "DEFERRED",
+            Self::Definer => "DEFINER",
+            Self::DeleteP => "DELETE_P",
+            Self::Delimiter => "DELIMITER",
+            Self::Delimiters => "DELIMITERS",
+            Self::Depends => "DEPENDS",
+            Self::Depth => "DEPTH",
+            Self::Desc => "DESC",
+            Self::Detach => "DETACH",
+            Self::Dictionary => "DICTIONARY",
+            Self::DisableP => "DISABLE_P",
+            Self::Discard => "DISCARD",
+            Self::Distinct => "DISTINCT",
+            Self::Do => "DO",
+            Self::DocumentP => "DOCUMENT_P",
+            Self::DomainP => "DOMAIN_P",
+            Self::DoubleP => "DOUBLE_P",
+            Self::Drop => "DROP",
+            Self::Each => "EACH",
+            Self::Else => "ELSE",
+            Self::EmptyP => "EMPTY_P",
+            Self::EnableP => "ENABLE_P",
+            Self::Encoding => "ENCODING",
+            Self::Encrypted => "ENCRYPTED",
+            Self::EndP => "END_P",
+            Self::EnumP => "ENUM_P",
+            Self::ErrorP => "ERROR_P",
+            Self::Escape => "ESCAPE",
+            Self::Event => "EVENT",
+            Self::Except => "EXCEPT",
+            Self::Exclude => "EXCLUDE",
+            Self::Excluding => "EXCLUDING",
+            Self::Exclusive => "EXCLUSIVE",
+            Self::Execute => "EXECUTE",
+            Self::Exists => "EXISTS",
+            Self::Explain => "EXPLAIN",
+            Self::Expression => "EXPRESSION",
+            Self::Extension => "EXTENSION",
+            Self::External => "EXTERNAL",
+            Self::Extract => "EXTRACT",
+            Self::FalseP => "FALSE_P",
+            Self::Family => "FAMILY",
+            Self::Fetch => "FETCH",
+            Self::Filter => "FILTER",
+            Self::Finalize => "FINALIZE",
+            Self::FirstP => "FIRST_P",
+            Self::FloatP => "FLOAT_P",
+            Self::Following => "FOLLOWING",
+            Self::For => "FOR",
+            Self::Force => "FORCE",
+            Self::Foreign => "FOREIGN",
+            Self::Format => "FORMAT",
+            Self::Forward => "FORWARD",
+            Self::Freeze => "FREEZE",
+            Self::From => "FROM",
+            Self::Full => "FULL",
+            Self::Function => "FUNCTION",
+            Self::Functions => "FUNCTIONS",
+            Self::Generated => "GENERATED",
+            Self::Global => "GLOBAL",
+            Self::Grant => "GRANT",
+            Self::Granted => "GRANTED",
+            Self::Greatest => "GREATEST",
+            Self::GroupP => "GROUP_P",
+            Self::Grouping => "GROUPING",
+            Self::Groups => "GROUPS",
+            Self::Handler => "HANDLER",
+            Self::Having => "HAVING",
+            Self::HeaderP => "HEADER_P",
+            Self::Hold => "HOLD",
+            Self::HourP => "HOUR_P",
+            Self::IdentityP => "IDENTITY_P",
+            Self::IfP => "IF_P",
+            Self::Ilike => "ILIKE",
+            Self::Immediate => "IMMEDIATE",
+            Self::Immutable => "IMMUTABLE",
+            Self::ImplicitP => "IMPLICIT_P",
+            Self::ImportP => "IMPORT_P",
+            Self::InP => "IN_P",
+            Self::Include => "INCLUDE",
+            Self::Including => "INCLUDING",
+            Self::Increment => "INCREMENT",
+            Self::Indent => "INDENT",
+            Self::Index => "INDEX",
+            Self::Indexes => "INDEXES",
+            Self::Inherit => "INHERIT",
+            Self::Inherits => "INHERITS",
+            Self::Initially => "INITIALLY",
+            Self::InlineP => "INLINE_P",
+            Self::InnerP => "INNER_P",
+            Self::Inout => "INOUT",
+            Self::InputP => "INPUT_P",
+            Self::Insensitive => "INSENSITIVE",
+            Self::Insert => "INSERT",
+            Self::Instead => "INSTEAD",
+            Self::IntP => "INT_P",
+            Self::Integer => "INTEGER",
+            Self::Intersect => "INTERSECT",
+            Self::Interval => "INTERVAL",
+            Self::Into => "INTO",
+            Self::Invoker => "INVOKER",
+            Self::Is => "IS",
+            Self::Isnull => "ISNULL",
+            Self::Isolation => "ISOLATION",
+            Self::Join => "JOIN",
+            Self::Json => "JSON",
+            Self::JsonArray => "JSON_ARRAY",
+            Self::JsonArrayagg => "JSON_ARRAYAGG",
+            Self::JsonExists => "JSON_EXISTS",
+            Self::JsonObject => "JSON_OBJECT",
+            Self::JsonObjectagg => "JSON_OBJECTAGG",
+            Self::JsonQuery => "JSON_QUERY",
+            Self::JsonScalar => "JSON_SCALAR",
+            Self::JsonSerialize => "JSON_SERIALIZE",
+            Self::JsonTable => "JSON_TABLE",
+            Self::JsonValue => "JSON_VALUE",
+            Self::Keep => "KEEP",
+            Self::Key => "KEY",
+            Self::Keys => "KEYS",
+            Self::Label => "LABEL",
+            Self::Language => "LANGUAGE",
+            Self::LargeP => "LARGE_P",
+            Self::LastP => "LAST_P",
+            Self::LateralP => "LATERAL_P",
+            Self::Leading => "LEADING",
+            Self::Leakproof => "LEAKPROOF",
+            Self::Least => "LEAST",
+            Self::Left => "LEFT",
+            Self::Level => "LEVEL",
+            Self::Like => "LIKE",
+            Self::Limit => "LIMIT",
+            Self::Listen => "LISTEN",
+            Self::Load => "LOAD",
+            Self::Local => "LOCAL",
+            Self::Localtime => "LOCALTIME",
+            Self::Localtimestamp => "LOCALTIMESTAMP",
+            Self::Location => "LOCATION",
+            Self::LockP => "LOCK_P",
+            Self::Locked => "LOCKED",
+            Self::Logged => "LOGGED",
+            Self::Mapping => "MAPPING",
+            Self::Match => "MATCH",
+            Self::Matched => "MATCHED",
+            Self::Materialized => "MATERIALIZED",
+            Self::Maxvalue => "MAXVALUE",
+            Self::Merge => "MERGE",
+            Self::MergeAction => "MERGE_ACTION",
+            Self::Method => "METHOD",
+            Self::MinuteP => "MINUTE_P",
+            Self::Minvalue => "MINVALUE",
+            Self::Mode => "MODE",
+            Self::MonthP => "MONTH_P",
+            Self::Move => "MOVE",
+            Self::NameP => "NAME_P",
+            Self::Names => "NAMES",
+            Self::National => "NATIONAL",
+            Self::Natural => "NATURAL",
+            Self::Nchar => "NCHAR",
+            Self::Nested => "NESTED",
+            Self::New => "NEW",
+            Self::Next => "NEXT",
+            Self::Nfc => "NFC",
+            Self::Nfd => "NFD",
+            Self::Nfkc => "NFKC",
+            Self::Nfkd => "NFKD",
+            Self::No => "NO",
+            Self::None => "NONE",
+            Self::Normalize => "NORMALIZE",
+            Self::Normalized => "NORMALIZED",
+            Self::Not => "NOT",
+            Self::Nothing => "NOTHING",
+            Self::Notify => "NOTIFY",
+            Self::Notnull => "NOTNULL",
+            Self::Nowait => "NOWAIT",
+            Self::NullP => "NULL_P",
+            Self::Nullif => "NULLIF",
+            Self::NullsP => "NULLS_P",
+            Self::Numeric => "NUMERIC",
+            Self::ObjectP => "OBJECT_P",
+            Self::Of => "OF",
+            Self::Off => "OFF",
+            Self::Offset => "OFFSET",
+            Self::Oids => "OIDS",
+            Self::Old => "OLD",
+            Self::Omit => "OMIT",
+            Self::On => "ON",
+            Self::Only => "ONLY",
+            Self::Operator => "OPERATOR",
+            Self::Option => "OPTION",
+            Self::Options => "OPTIONS",
+            Self::Or => "OR",
+            Self::Order => "ORDER",
+            Self::Ordinality => "ORDINALITY",
+            Self::Others => "OTHERS",
+            Self::OutP => "OUT_P",
+            Self::OuterP => "OUTER_P",
+            Self::Over => "OVER",
+            Self::Overlaps => "OVERLAPS",
+            Self::Overlay => "OVERLAY",
+            Self::Overriding => "OVERRIDING",
+            Self::Owned => "OWNED",
+            Self::Owner => "OWNER",
+            Self::Parallel => "PARALLEL",
+            Self::Parameter => "PARAMETER",
+            Self::Parser => "PARSER",
+            Self::Partial => "PARTIAL",
+            Self::Partition => "PARTITION",
+            Self::Passing => "PASSING",
+            Self::Password => "PASSWORD",
+            Self::Path => "PATH",
+            Self::Placing => "PLACING",
+            Self::Plan => "PLAN",
+            Self::Plans => "PLANS",
+            Self::Policy => "POLICY",
+            Self::Position => "POSITION",
+            Self::Preceding => "PRECEDING",
+            Self::Precision => "PRECISION",
+            Self::Preserve => "PRESERVE",
+            Self::Prepare => "PREPARE",
+            Self::Prepared => "PREPARED",
+            Self::Primary => "PRIMARY",
+            Self::Prior => "PRIOR",
+            Self::Privileges => "PRIVILEGES",
+            Self::Procedural => "PROCEDURAL",
+            Self::Procedure => "PROCEDURE",
+            Self::Procedures => "PROCEDURES",
+            Self::Program => "PROGRAM",
+            Self::Publication => "PUBLICATION",
+            Self::Quote => "QUOTE",
+            Self::Quotes => "QUOTES",
+            Self::Range => "RANGE",
+            Self::Read => "READ",
+            Self::Real => "REAL",
+            Self::Reassign => "REASSIGN",
+            Self::Recheck => "RECHECK",
+            Self::Recursive => "RECURSIVE",
+            Self::RefP => "REF_P",
+            Self::References => "REFERENCES",
+            Self::Referencing => "REFERENCING",
+            Self::Refresh => "REFRESH",
+            Self::Reindex => "REINDEX",
+            Self::RelativeP => "RELATIVE_P",
+            Self::Release => "RELEASE",
+            Self::Rename => "RENAME",
+            Self::Repeatable => "REPEATABLE",
+            Self::Replace => "REPLACE",
+            Self::Replica => "REPLICA",
+            Self::Reset => "RESET",
+            Self::Restart => "RESTART",
+            Self::Restrict => "RESTRICT",
+            Self::Return => "RETURN",
+            Self::Returning => "RETURNING",
+            Self::Returns => "RETURNS",
+            Self::Revoke => "REVOKE",
+            Self::Right => "RIGHT",
+            Self::Role => "ROLE",
+            Self::Rollback => "ROLLBACK",
+            Self::Rollup => "ROLLUP",
+            Self::Routine => "ROUTINE",
+            Self::Routines => "ROUTINES",
+            Self::Row => "ROW",
+            Self::Rows => "ROWS",
+            Self::Rule => "RULE",
+            Self::Savepoint => "SAVEPOINT",
+            Self::Scalar => "SCALAR",
+            Self::Schema => "SCHEMA",
+            Self::Schemas => "SCHEMAS",
+            Self::Scroll => "SCROLL",
+            Self::Search => "SEARCH",
+            Self::SecondP => "SECOND_P",
+            Self::Security => "SECURITY",
+            Self::Select => "SELECT",
+            Self::Sequence => "SEQUENCE",
+            Self::Sequences => "SEQUENCES",
+            Self::Serializable => "SERIALIZABLE",
+            Self::Server => "SERVER",
+            Self::Session => "SESSION",
+            Self::SessionUser => "SESSION_USER",
+            Self::Set => "SET",
+            Self::Sets => "SETS",
+            Self::Setof => "SETOF",
+            Self::Share => "SHARE",
+            Self::Show => "SHOW",
+            Self::Similar => "SIMILAR",
+            Self::Simple => "SIMPLE",
+            Self::Skip => "SKIP",
+            Self::Smallint => "SMALLINT",
+            Self::Snapshot => "SNAPSHOT",
+            Self::Some => "SOME",
+            Self::Source => "SOURCE",
+            Self::SqlP => "SQL_P",
+            Self::Stable => "STABLE",
+            Self::StandaloneP => "STANDALONE_P",
+            Self::Start => "START",
+            Self::Statement => "STATEMENT",
+            Self::Statistics => "STATISTICS",
+            Self::Stdin => "STDIN",
+            Self::Stdout => "STDOUT",
+            Self::Storage => "STORAGE",
+            Self::Stored => "STORED",
+            Self::StrictP => "STRICT_P",
+            Self::StringP => "STRING_P",
+            Self::StripP => "STRIP_P",
+            Self::Subscription => "SUBSCRIPTION",
+            Self::Substring => "SUBSTRING",
+            Self::Support => "SUPPORT",
+            Self::Symmetric => "SYMMETRIC",
+            Self::Sysid => "SYSID",
+            Self::SystemP => "SYSTEM_P",
+            Self::SystemUser => "SYSTEM_USER",
+            Self::Table => "TABLE",
+            Self::Tables => "TABLES",
+            Self::Tablesample => "TABLESAMPLE",
+            Self::Tablespace => "TABLESPACE",
+            Self::Target => "TARGET",
+            Self::Temp => "TEMP",
+            Self::Template => "TEMPLATE",
+            Self::Temporary => "TEMPORARY",
+            Self::TextP => "TEXT_P",
+            Self::Then => "THEN",
+            Self::Ties => "TIES",
+            Self::Time => "TIME",
+            Self::Timestamp => "TIMESTAMP",
+            Self::To => "TO",
+            Self::Trailing => "TRAILING",
+            Self::Transaction => "TRANSACTION",
+            Self::Transform => "TRANSFORM",
+            Self::Treat => "TREAT",
+            Self::Trigger => "TRIGGER",
+            Self::Trim => "TRIM",
+            Self::TrueP => "TRUE_P",
+            Self::Truncate => "TRUNCATE",
+            Self::Trusted => "TRUSTED",
+            Self::TypeP => "TYPE_P",
+            Self::TypesP => "TYPES_P",
+            Self::Uescape => "UESCAPE",
+            Self::Unbounded => "UNBOUNDED",
+            Self::Unconditional => "UNCONDITIONAL",
+            Self::Uncommitted => "UNCOMMITTED",
+            Self::Unencrypted => "UNENCRYPTED",
+            Self::Union => "UNION",
+            Self::Unique => "UNIQUE",
+            Self::Unknown => "UNKNOWN",
+            Self::Unlisten => "UNLISTEN",
+            Self::Unlogged => "UNLOGGED",
+            Self::Until => "UNTIL",
+            Self::Update => "UPDATE",
+            Self::User => "USER",
+            Self::Using => "USING",
+            Self::Vacuum => "VACUUM",
+            Self::Valid => "VALID",
+            Self::Validate => "VALIDATE",
+            Self::Validator => "VALIDATOR",
+            Self::ValueP => "VALUE_P",
+            Self::Values => "VALUES",
+            Self::Varchar => "VARCHAR",
+            Self::Variadic => "VARIADIC",
+            Self::Varying => "VARYING",
+            Self::Verbose => "VERBOSE",
+            Self::VersionP => "VERSION_P",
+            Self::View => "VIEW",
+            Self::Views => "VIEWS",
+            Self::Volatile => "VOLATILE",
+            Self::When => "WHEN",
+            Self::Where => "WHERE",
+            Self::WhitespaceP => "WHITESPACE_P",
+            Self::Window => "WINDOW",
+            Self::With => "WITH",
+            Self::Within => "WITHIN",
+            Self::Without => "WITHOUT",
+            Self::Work => "WORK",
+            Self::Wrapper => "WRAPPER",
+            Self::Write => "WRITE",
+            Self::XmlP => "XML_P",
+            Self::Xmlattributes => "XMLATTRIBUTES",
+            Self::Xmlconcat => "XMLCONCAT",
+            Self::Xmlelement => "XMLELEMENT",
+            Self::Xmlexists => "XMLEXISTS",
+            Self::Xmlforest => "XMLFOREST",
+            Self::Xmlnamespaces => "XMLNAMESPACES",
+            Self::Xmlparse => "XMLPARSE",
+            Self::Xmlpi => "XMLPI",
+            Self::Xmlroot => "XMLROOT",
+            Self::Xmlserialize => "XMLSERIALIZE",
+            Self::Xmltable => "XMLTABLE",
+            Self::YearP => "YEAR_P",
+            Self::YesP => "YES_P",
+            Self::Zone => "ZONE",
+            Self::FormatLa => "FORMAT_LA",
+            Self::NotLa => "NOT_LA",
+            Self::NullsLa => "NULLS_LA",
+            Self::WithLa => "WITH_LA",
+            Self::WithoutLa => "WITHOUT_LA",
+            Self::ModeTypeName => "MODE_TYPE_NAME",
+            Self::ModePlpgsqlExpr => "MODE_PLPGSQL_EXPR",
+            Self::ModePlpgsqlAssign1 => "MODE_PLPGSQL_ASSIGN1",
+            Self::ModePlpgsqlAssign2 => "MODE_PLPGSQL_ASSIGN2",
+            Self::ModePlpgsqlAssign3 => "MODE_PLPGSQL_ASSIGN3",
+            Self::Uminus => "UMINUS",
+        }
+    }
+    /// Creates an enum from field names used in the ProtoBuf definition.
+    pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
+        match value {
+            "NUL" => Some(Self::Nul),
+            "ASCII_36" => Some(Self::Ascii36),
+            "ASCII_37" => Some(Self::Ascii37),
+            "ASCII_40" => Some(Self::Ascii40),
+            "ASCII_41" => Some(Self::Ascii41),
+            "ASCII_42" => Some(Self::Ascii42),
+            "ASCII_43" => Some(Self::Ascii43),
+            "ASCII_44" => Some(Self::Ascii44),
+            "ASCII_45" => Some(Self::Ascii45),
+            "ASCII_46" => Some(Self::Ascii46),
+            "ASCII_47" => Some(Self::Ascii47),
+            "ASCII_58" => Some(Self::Ascii58),
+            "ASCII_59" => Some(Self::Ascii59),
+            "ASCII_60" => Some(Self::Ascii60),
+            "ASCII_61" => Some(Self::Ascii61),
+            "ASCII_62" => Some(Self::Ascii62),
+            "ASCII_63" => Some(Self::Ascii63),
+            "ASCII_91" => Some(Self::Ascii91),
+            "ASCII_92" => Some(Self::Ascii92),
+            "ASCII_93" => Some(Self::Ascii93),
+            "ASCII_94" => Some(Self::Ascii94),
+            "IDENT" => Some(Self::Ident),
+            "UIDENT" => Some(Self::Uident),
+            "FCONST" => Some(Self::Fconst),
+            "SCONST" => Some(Self::Sconst),
+            "USCONST" => Some(Self::Usconst),
+            "BCONST" => Some(Self::Bconst),
+            "XCONST" => Some(Self::Xconst),
+            "Op" => Some(Self::Op),
+            "ICONST" => Some(Self::Iconst),
+            "PARAM" => Some(Self::Param),
+            "TYPECAST" => Some(Self::Typecast),
+            "DOT_DOT" => Some(Self::DotDot),
+            "COLON_EQUALS" => Some(Self::ColonEquals),
+            "EQUALS_GREATER" => Some(Self::EqualsGreater),
+            "LESS_EQUALS" => Some(Self::LessEquals),
+            "GREATER_EQUALS" => Some(Self::GreaterEquals),
+            "NOT_EQUALS" => Some(Self::NotEquals),
+            "SQL_COMMENT" => Some(Self::SqlComment),
+            "C_COMMENT" => Some(Self::CComment),
+            "ABORT_P" => Some(Self::AbortP),
+            "ABSENT" => Some(Self::Absent),
+            "ABSOLUTE_P" => Some(Self::AbsoluteP),
+            "ACCESS" => Some(Self::Access),
+            "ACTION" => Some(Self::Action),
+            "ADD_P" => Some(Self::AddP),
+            "ADMIN" => Some(Self::Admin),
+            "AFTER" => Some(Self::After),
+            "AGGREGATE" => Some(Self::Aggregate),
+            "ALL" => Some(Self::All),
+            "ALSO" => Some(Self::Also),
+            "ALTER" => Some(Self::Alter),
+            "ALWAYS" => Some(Self::Always),
+            "ANALYSE" => Some(Self::Analyse),
+            "ANALYZE" => Some(Self::Analyze),
+            "AND" => Some(Self::And),
+            "ANY" => Some(Self::Any),
+            "ARRAY" => Some(Self::Array),
+            "AS" => Some(Self::As),
+            "ASC" => Some(Self::Asc),
+            "ASENSITIVE" => Some(Self::Asensitive),
+            "ASSERTION" => Some(Self::Assertion),
+            "ASSIGNMENT" => Some(Self::Assignment),
+            "ASYMMETRIC" => Some(Self::Asymmetric),
+            "ATOMIC" => Some(Self::Atomic),
+            "AT" => Some(Self::At),
+            "ATTACH" => Some(Self::Attach),
+            "ATTRIBUTE" => Some(Self::Attribute),
+            "AUTHORIZATION" => Some(Self::Authorization),
+            "BACKWARD" => Some(Self::Backward),
+            "BEFORE" => Some(Self::Before),
+            "BEGIN_P" => Some(Self::BeginP),
+            "BETWEEN" => Some(Self::Between),
+            "BIGINT" => Some(Self::Bigint),
+            "BINARY" => Some(Self::Binary),
+            "BIT" => Some(Self::Bit),
+            "BOOLEAN_P" => Some(Self::BooleanP),
+            "BOTH" => Some(Self::Both),
+            "BREADTH" => Some(Self::Breadth),
+            "BY" => Some(Self::By),
+            "CACHE" => Some(Self::Cache),
+            "CALL" => Some(Self::Call),
+            "CALLED" => Some(Self::Called),
+            "CASCADE" => Some(Self::Cascade),
+            "CASCADED" => Some(Self::Cascaded),
+            "CASE" => Some(Self::Case),
+            "CAST" => Some(Self::Cast),
+            "CATALOG_P" => Some(Self::CatalogP),
+            "CHAIN" => Some(Self::Chain),
+            "CHAR_P" => Some(Self::CharP),
+            "CHARACTER" => Some(Self::Character),
+            "CHARACTERISTICS" => Some(Self::Characteristics),
+            "CHECK" => Some(Self::Check),
+            "CHECKPOINT" => Some(Self::Checkpoint),
+            "CLASS" => Some(Self::Class),
+            "CLOSE" => Some(Self::Close),
+            "CLUSTER" => Some(Self::Cluster),
+            "COALESCE" => Some(Self::Coalesce),
+            "COLLATE" => Some(Self::Collate),
+            "COLLATION" => Some(Self::Collation),
+            "COLUMN" => Some(Self::Column),
+            "COLUMNS" => Some(Self::Columns),
+            "COMMENT" => Some(Self::Comment),
+            "COMMENTS" => Some(Self::Comments),
+            "COMMIT" => Some(Self::Commit),
+            "COMMITTED" => Some(Self::Committed),
+            "COMPRESSION" => Some(Self::Compression),
+            "CONCURRENTLY" => Some(Self::Concurrently),
+            "CONDITIONAL" => Some(Self::Conditional),
+            "CONFIGURATION" => Some(Self::Configuration),
+            "CONFLICT" => Some(Self::Conflict),
+            "CONNECTION" => Some(Self::Connection),
+            "CONSTRAINT" => Some(Self::Constraint),
+            "CONSTRAINTS" => Some(Self::Constraints),
+            "CONTENT_P" => Some(Self::ContentP),
+            "CONTINUE_P" => Some(Self::ContinueP),
+            "CONVERSION_P" => Some(Self::ConversionP),
+            "COPY" => Some(Self::Copy),
+            "COST" => Some(Self::Cost),
+            "CREATE" => Some(Self::Create),
+            "CROSS" => Some(Self::Cross),
+            "CSV" => Some(Self::Csv),
+            "CUBE" => Some(Self::Cube),
+            "CURRENT_P" => Some(Self::CurrentP),
+            "CURRENT_CATALOG" => Some(Self::CurrentCatalog),
+            "CURRENT_DATE" => Some(Self::CurrentDate),
+            "CURRENT_ROLE" => Some(Self::CurrentRole),
+            "CURRENT_SCHEMA" => Some(Self::CurrentSchema),
+            "CURRENT_TIME" => Some(Self::CurrentTime),
+            "CURRENT_TIMESTAMP" => Some(Self::CurrentTimestamp),
+            "CURRENT_USER" => Some(Self::CurrentUser),
+            "CURSOR" => Some(Self::Cursor),
+            "CYCLE" => Some(Self::Cycle),
+            "DATA_P" => Some(Self::DataP),
+            "DATABASE" => Some(Self::Database),
+            "DAY_P" => Some(Self::DayP),
+            "DEALLOCATE" => Some(Self::Deallocate),
+            "DEC" => Some(Self::Dec),
+            "DECIMAL_P" => Some(Self::DecimalP),
+            "DECLARE" => Some(Self::Declare),
+            "DEFAULT" => Some(Self::Default),
+            "DEFAULTS" => Some(Self::Defaults),
+            "DEFERRABLE" => Some(Self::Deferrable),
+            "DEFERRED" => Some(Self::Deferred),
+            "DEFINER" => Some(Self::Definer),
+            "DELETE_P" => Some(Self::DeleteP),
+            "DELIMITER" => Some(Self::Delimiter),
+            "DELIMITERS" => Some(Self::Delimiters),
+            "DEPENDS" => Some(Self::Depends),
+            "DEPTH" => Some(Self::Depth),
+            "DESC" => Some(Self::Desc),
+            "DETACH" => Some(Self::Detach),
+            "DICTIONARY" => Some(Self::Dictionary),
+            "DISABLE_P" => Some(Self::DisableP),
+            "DISCARD" => Some(Self::Discard),
+            "DISTINCT" => Some(Self::Distinct),
+            "DO" => Some(Self::Do),
+            "DOCUMENT_P" => Some(Self::DocumentP),
+            "DOMAIN_P" => Some(Self::DomainP),
+            "DOUBLE_P" => Some(Self::DoubleP),
+            "DROP" => Some(Self::Drop),
+            "EACH" => Some(Self::Each),
+            "ELSE" => Some(Self::Else),
+            "EMPTY_P" => Some(Self::EmptyP),
+            "ENABLE_P" => Some(Self::EnableP),
+            "ENCODING" => Some(Self::Encoding),
+            "ENCRYPTED" => Some(Self::Encrypted),
+            "END_P" => Some(Self::EndP),
+            "ENUM_P" => Some(Self::EnumP),
+            "ERROR_P" => Some(Self::ErrorP),
+            "ESCAPE" => Some(Self::Escape),
+            "EVENT" => Some(Self::Event),
+            "EXCEPT" => Some(Self::Except),
+            "EXCLUDE" => Some(Self::Exclude),
+            "EXCLUDING" => Some(Self::Excluding),
+            "EXCLUSIVE" => Some(Self::Exclusive),
+            "EXECUTE" => Some(Self::Execute),
+            "EXISTS" => Some(Self::Exists),
+            "EXPLAIN" => Some(Self::Explain),
+            "EXPRESSION" => Some(Self::Expression),
+            "EXTENSION" => Some(Self::Extension),
+            "EXTERNAL" => Some(Self::External),
+            "EXTRACT" => Some(Self::Extract),
+            "FALSE_P" => Some(Self::FalseP),
+            "FAMILY" => Some(Self::Family),
+            "FETCH" => Some(Self::Fetch),
+            "FILTER" => Some(Self::Filter),
+            "FINALIZE" => Some(Self::Finalize),
+            "FIRST_P" => Some(Self::FirstP),
+            "FLOAT_P" => Some(Self::FloatP),
+            "FOLLOWING" => Some(Self::Following),
+            "FOR" => Some(Self::For),
+            "FORCE" => Some(Self::Force),
+            "FOREIGN" => Some(Self::Foreign),
+            "FORMAT" => Some(Self::Format),
+            "FORWARD" => Some(Self::Forward),
+            "FREEZE" => Some(Self::Freeze),
+            "FROM" => Some(Self::From),
+            "FULL" => Some(Self::Full),
+            "FUNCTION" => Some(Self::Function),
+            "FUNCTIONS" => Some(Self::Functions),
+            "GENERATED" => Some(Self::Generated),
+            "GLOBAL" => Some(Self::Global),
+            "GRANT" => Some(Self::Grant),
+            "GRANTED" => Some(Self::Granted),
+            "GREATEST" => Some(Self::Greatest),
+            "GROUP_P" => Some(Self::GroupP),
+            "GROUPING" => Some(Self::Grouping),
+            "GROUPS" => Some(Self::Groups),
+            "HANDLER" => Some(Self::Handler),
+            "HAVING" => Some(Self::Having),
+            "HEADER_P" => Some(Self::HeaderP),
+            "HOLD" => Some(Self::Hold),
+            "HOUR_P" => Some(Self::HourP),
+            "IDENTITY_P" => Some(Self::IdentityP),
+            "IF_P" => Some(Self::IfP),
+            "ILIKE" => Some(Self::Ilike),
+            "IMMEDIATE" => Some(Self::Immediate),
+            "IMMUTABLE" => Some(Self::Immutable),
+            "IMPLICIT_P" => Some(Self::ImplicitP),
+            "IMPORT_P" => Some(Self::ImportP),
+            "IN_P" => Some(Self::InP),
+            "INCLUDE" => Some(Self::Include),
+            "INCLUDING" => Some(Self::Including),
+            "INCREMENT" => Some(Self::Increment),
+            "INDENT" => Some(Self::Indent),
+            "INDEX" => Some(Self::Index),
+            "INDEXES" => Some(Self::Indexes),
+            "INHERIT" => Some(Self::Inherit),
+            "INHERITS" => Some(Self::Inherits),
+            "INITIALLY" => Some(Self::Initially),
+            "INLINE_P" => Some(Self::InlineP),
+            "INNER_P" => Some(Self::InnerP),
+            "INOUT" => Some(Self::Inout),
+            "INPUT_P" => Some(Self::InputP),
+            "INSENSITIVE" => Some(Self::Insensitive),
+            "INSERT" => Some(Self::Insert),
+            "INSTEAD" => Some(Self::Instead),
+            "INT_P" => Some(Self::IntP),
+            "INTEGER" => Some(Self::Integer),
+            "INTERSECT" => Some(Self::Intersect),
+            "INTERVAL" => Some(Self::Interval),
+            "INTO" => Some(Self::Into),
+            "INVOKER" => Some(Self::Invoker),
+            "IS" => Some(Self::Is),
+            "ISNULL" => Some(Self::Isnull),
+            "ISOLATION" => Some(Self::Isolation),
+            "JOIN" => Some(Self::Join),
+            "JSON" => Some(Self::Json),
+            "JSON_ARRAY" => Some(Self::JsonArray),
+            "JSON_ARRAYAGG" => Some(Self::JsonArrayagg),
+            "JSON_EXISTS" => Some(Self::JsonExists),
+            "JSON_OBJECT" => Some(Self::JsonObject),
+            "JSON_OBJECTAGG" => Some(Self::JsonObjectagg),
+            "JSON_QUERY" => Some(Self::JsonQuery),
+            "JSON_SCALAR" => Some(Self::JsonScalar),
+            "JSON_SERIALIZE" => Some(Self::JsonSerialize),
+            "JSON_TABLE" => Some(Self::JsonTable),
+            "JSON_VALUE" => Some(Self::JsonValue),
+            "KEEP" => Some(Self::Keep),
+            "KEY" => Some(Self::Key),
+            "KEYS" => Some(Self::Keys),
+            "LABEL" => Some(Self::Label),
+            "LANGUAGE" => Some(Self::Language),
+            "LARGE_P" => Some(Self::LargeP),
+            "LAST_P" => Some(Self::LastP),
+            "LATERAL_P" => Some(Self::LateralP),
+            "LEADING" => Some(Self::Leading),
+            "LEAKPROOF" => Some(Self::Leakproof),
+            "LEAST" => Some(Self::Least),
+            "LEFT" => Some(Self::Left),
+            "LEVEL" => Some(Self::Level),
+            "LIKE" => Some(Self::Like),
+            "LIMIT" => Some(Self::Limit),
+            "LISTEN" => Some(Self::Listen),
+            "LOAD" => Some(Self::Load),
+            "LOCAL" => Some(Self::Local),
+            "LOCALTIME" => Some(Self::Localtime),
+            "LOCALTIMESTAMP" => Some(Self::Localtimestamp),
+            "LOCATION" => Some(Self::Location),
+            "LOCK_P" => Some(Self::LockP),
+            "LOCKED" => Some(Self::Locked),
+            "LOGGED" => Some(Self::Logged),
+            "MAPPING" => Some(Self::Mapping),
+            "MATCH" => Some(Self::Match),
+            "MATCHED" => Some(Self::Matched),
+            "MATERIALIZED" => Some(Self::Materialized),
+            "MAXVALUE" => Some(Self::Maxvalue),
+            "MERGE" => Some(Self::Merge),
+            "MERGE_ACTION" => Some(Self::MergeAction),
+            "METHOD" => Some(Self::Method),
+            "MINUTE_P" => Some(Self::MinuteP),
+            "MINVALUE" => Some(Self::Minvalue),
+            "MODE" => Some(Self::Mode),
+            "MONTH_P" => Some(Self::MonthP),
+            "MOVE" => Some(Self::Move),
+            "NAME_P" => Some(Self::NameP),
+            "NAMES" => Some(Self::Names),
+            "NATIONAL" => Some(Self::National),
+            "NATURAL" => Some(Self::Natural),
+            "NCHAR" => Some(Self::Nchar),
+            "NESTED" => Some(Self::Nested),
+            "NEW" => Some(Self::New),
+            "NEXT" => Some(Self::Next),
+            "NFC" => Some(Self::Nfc),
+            "NFD" => Some(Self::Nfd),
+            "NFKC" => Some(Self::Nfkc),
+            "NFKD" => Some(Self::Nfkd),
+            "NO" => Some(Self::No),
+            "NONE" => Some(Self::None),
+            "NORMALIZE" => Some(Self::Normalize),
+            "NORMALIZED" => Some(Self::Normalized),
+            "NOT" => Some(Self::Not),
+            "NOTHING" => Some(Self::Nothing),
+            "NOTIFY" => Some(Self::Notify),
+            "NOTNULL" => Some(Self::Notnull),
+            "NOWAIT" => Some(Self::Nowait),
+            "NULL_P" => Some(Self::NullP),
+            "NULLIF" => Some(Self::Nullif),
+            "NULLS_P" => Some(Self::NullsP),
+            "NUMERIC" => Some(Self::Numeric),
+            "OBJECT_P" => Some(Self::ObjectP),
+            "OF" => Some(Self::Of),
+            "OFF" => Some(Self::Off),
+            "OFFSET" => Some(Self::Offset),
+            "OIDS" => Some(Self::Oids),
+            "OLD" => Some(Self::Old),
+            "OMIT" => Some(Self::Omit),
+            "ON" => Some(Self::On),
+            "ONLY" => Some(Self::Only),
+            "OPERATOR" => Some(Self::Operator),
+            "OPTION" => Some(Self::Option),
+            "OPTIONS" => Some(Self::Options),
+            "OR" => Some(Self::Or),
+            "ORDER" => Some(Self::Order),
+            "ORDINALITY" => Some(Self::Ordinality),
+            "OTHERS" => Some(Self::Others),
+            "OUT_P" => Some(Self::OutP),
+            "OUTER_P" => Some(Self::OuterP),
+            "OVER" => Some(Self::Over),
+            "OVERLAPS" => Some(Self::Overlaps),
+            "OVERLAY" => Some(Self::Overlay),
+            "OVERRIDING" => Some(Self::Overriding),
+            "OWNED" => Some(Self::Owned),
+            "OWNER" => Some(Self::Owner),
+            "PARALLEL" => Some(Self::Parallel),
+            "PARAMETER" => Some(Self::Parameter),
+            "PARSER" => Some(Self::Parser),
+            "PARTIAL" => Some(Self::Partial),
+            "PARTITION" => Some(Self::Partition),
+            "PASSING" => Some(Self::Passing),
+            "PASSWORD" => Some(Self::Password),
+            "PATH" => Some(Self::Path),
+            "PLACING" => Some(Self::Placing),
+            "PLAN" => Some(Self::Plan),
+            "PLANS" => Some(Self::Plans),
+            "POLICY" => Some(Self::Policy),
+            "POSITION" => Some(Self::Position),
+            "PRECEDING" => Some(Self::Preceding),
+            "PRECISION" => Some(Self::Precision),
+            "PRESERVE" => Some(Self::Preserve),
+            "PREPARE" => Some(Self::Prepare),
+            "PREPARED" => Some(Self::Prepared),
+            "PRIMARY" => Some(Self::Primary),
+            "PRIOR" => Some(Self::Prior),
+            "PRIVILEGES" => Some(Self::Privileges),
+            "PROCEDURAL" => Some(Self::Procedural),
+            "PROCEDURE" => Some(Self::Procedure),
+            "PROCEDURES" => Some(Self::Procedures),
+            "PROGRAM" => Some(Self::Program),
+            "PUBLICATION" => Some(Self::Publication),
+            "QUOTE" => Some(Self::Quote),
+            "QUOTES" => Some(Self::Quotes),
+            "RANGE" => Some(Self::Range),
+            "READ" => Some(Self::Read),
+            "REAL" => Some(Self::Real),
+            "REASSIGN" => Some(Self::Reassign),
+            "RECHECK" => Some(Self::Recheck),
+            "RECURSIVE" => Some(Self::Recursive),
+            "REF_P" => Some(Self::RefP),
+            "REFERENCES" => Some(Self::References),
+            "REFERENCING" => Some(Self::Referencing),
+            "REFRESH" => Some(Self::Refresh),
+            "REINDEX" => Some(Self::Reindex),
+            "RELATIVE_P" => Some(Self::RelativeP),
+            "RELEASE" => Some(Self::Release),
+            "RENAME" => Some(Self::Rename),
+            "REPEATABLE" => Some(Self::Repeatable),
+            "REPLACE" => Some(Self::Replace),
+            "REPLICA" => Some(Self::Replica),
+            "RESET" => Some(Self::Reset),
+            "RESTART" => Some(Self::Restart),
+            "RESTRICT" => Some(Self::Restrict),
+            "RETURN" => Some(Self::Return),
+            "RETURNING" => Some(Self::Returning),
+            "RETURNS" => Some(Self::Returns),
+            "REVOKE" => Some(Self::Revoke),
+            "RIGHT" => Some(Self::Right),
+            "ROLE" => Some(Self::Role),
+            "ROLLBACK" => Some(Self::Rollback),
+            "ROLLUP" => Some(Self::Rollup),
+            "ROUTINE" => Some(Self::Routine),
+            "ROUTINES" => Some(Self::Routines),
+            "ROW" => Some(Self::Row),
+            "ROWS" => Some(Self::Rows),
+            "RULE" => Some(Self::Rule),
+            "SAVEPOINT" => Some(Self::Savepoint),
+            "SCALAR" => Some(Self::Scalar),
+            "SCHEMA" => Some(Self::Schema),
+            "SCHEMAS" => Some(Self::Schemas),
+            "SCROLL" => Some(Self::Scroll),
+            "SEARCH" => Some(Self::Search),
+            "SECOND_P" => Some(Self::SecondP),
+            "SECURITY" => Some(Self::Security),
+            "SELECT" => Some(Self::Select),
+            "SEQUENCE" => Some(Self::Sequence),
+            "SEQUENCES" => Some(Self::Sequences),
+            "SERIALIZABLE" => Some(Self::Serializable),
+            "SERVER" => Some(Self::Server),
+            "SESSION" => Some(Self::Session),
+            "SESSION_USER" => Some(Self::SessionUser),
+            "SET" => Some(Self::Set),
+            "SETS" => Some(Self::Sets),
+            "SETOF" => Some(Self::Setof),
+            "SHARE" => Some(Self::Share),
+            "SHOW" => Some(Self::Show),
+            "SIMILAR" => Some(Self::Similar),
+            "SIMPLE" => Some(Self::Simple),
+            "SKIP" => Some(Self::Skip),
+            "SMALLINT" => Some(Self::Smallint),
+            "SNAPSHOT" => Some(Self::Snapshot),
+            "SOME" => Some(Self::Some),
+            "SOURCE" => Some(Self::Source),
+            "SQL_P" => Some(Self::SqlP),
+            "STABLE" => Some(Self::Stable),
+            "STANDALONE_P" => Some(Self::StandaloneP),
+            "START" => Some(Self::Start),
+            "STATEMENT" => Some(Self::Statement),
+            "STATISTICS" => Some(Self::Statistics),
+            "STDIN" => Some(Self::Stdin),
+            "STDOUT" => Some(Self::Stdout),
+            "STORAGE" => Some(Self::Storage),
+            "STORED" => Some(Self::Stored),
+            "STRICT_P" => Some(Self::StrictP),
+            "STRING_P" => Some(Self::StringP),
+            "STRIP_P" => Some(Self::StripP),
+            "SUBSCRIPTION" => Some(Self::Subscription),
+            "SUBSTRING" => Some(Self::Substring),
+            "SUPPORT" => Some(Self::Support),
+            "SYMMETRIC" => Some(Self::Symmetric),
+            "SYSID" => Some(Self::Sysid),
+            "SYSTEM_P" => Some(Self::SystemP),
+            "SYSTEM_USER" => Some(Self::SystemUser),
+            "TABLE" => Some(Self::Table),
+            "TABLES" => Some(Self::Tables),
+            "TABLESAMPLE" => Some(Self::Tablesample),
+            "TABLESPACE" => Some(Self::Tablespace),
+            "TARGET" => Some(Self::Target),
+            "TEMP" => Some(Self::Temp),
+            "TEMPLATE" => Some(Self::Template),
+            "TEMPORARY" => Some(Self::Temporary),
+            "TEXT_P" => Some(Self::TextP),
+            "THEN" => Some(Self::Then),
+            "TIES" => Some(Self::Ties),
+            "TIME" => Some(Self::Time),
+            "TIMESTAMP" => Some(Self::Timestamp),
+            "TO" => Some(Self::To),
+            "TRAILING" => Some(Self::Trailing),
+            "TRANSACTION" => Some(Self::Transaction),
+            "TRANSFORM" => Some(Self::Transform),
+            "TREAT" => Some(Self::Treat),
+            "TRIGGER" => Some(Self::Trigger),
+            "TRIM" => Some(Self::Trim),
+            "TRUE_P" => Some(Self::TrueP),
+            "TRUNCATE" => Some(Self::Truncate),
+            "TRUSTED" => Some(Self::Trusted),
+            "TYPE_P" => Some(Self::TypeP),
+            "TYPES_P" => Some(Self::TypesP),
+            "UESCAPE" => Some(Self::Uescape),
+            "UNBOUNDED" => Some(Self::Unbounded),
+            "UNCONDITIONAL" => Some(Self::Unconditional),
+            "UNCOMMITTED" => Some(Self::Uncommitted),
+            "UNENCRYPTED" => Some(Self::Unencrypted),
+            "UNION" => Some(Self::Union),
+            "UNIQUE" => Some(Self::Unique),
+            "UNKNOWN" => Some(Self::Unknown),
+            "UNLISTEN" => Some(Self::Unlisten),
+            "UNLOGGED" => Some(Self::Unlogged),
+            "UNTIL" => Some(Self::Until),
+            "UPDATE" => Some(Self::Update),
+            "USER" => Some(Self::User),
+            "USING" => Some(Self::Using),
+            "VACUUM" => Some(Self::Vacuum),
+            "VALID" => Some(Self::Valid),
+            "VALIDATE" => Some(Self::Validate),
+            "VALIDATOR" => Some(Self::Validator),
+            "VALUE_P" => Some(Self::ValueP),
+            "VALUES" => Some(Self::Values),
+            "VARCHAR" => Some(Self::Varchar),
+            "VARIADIC" => Some(Self::Variadic),
+            "VARYING" => Some(Self::Varying),
+            "VERBOSE" => Some(Self::Verbose),
+            "VERSION_P" => Some(Self::VersionP),
+            "VIEW" => Some(Self::View),
+            "VIEWS" => Some(Self::Views),
+            "VOLATILE" => Some(Self::Volatile),
+            "WHEN" => Some(Self::When),
+            "WHERE" => Some(Self::Where),
+            "WHITESPACE_P" => Some(Self::WhitespaceP),
+            "WINDOW" => Some(Self::Window),
+            "WITH" => Some(Self::With),
+            "WITHIN" => Some(Self::Within),
+            "WITHOUT" => Some(Self::Without),
+            "WORK" => Some(Self::Work),
+            "WRAPPER" => Some(Self::Wrapper),
+            "WRITE" => Some(Self::Write),
+            "XML_P" => Some(Self::XmlP),
+            "XMLATTRIBUTES" => Some(Self::Xmlattributes),
+            "XMLCONCAT" => Some(Self::Xmlconcat),
+            "XMLELEMENT" => Some(Self::Xmlelement),
+            "XMLEXISTS" => Some(Self::Xmlexists),
+            "XMLFOREST" => Some(Self::Xmlforest),
+            "XMLNAMESPACES" => Some(Self::Xmlnamespaces),
+            "XMLPARSE" => Some(Self::Xmlparse),
+            "XMLPI" => Some(Self::Xmlpi),
+            "XMLROOT" => Some(Self::Xmlroot),
+            "XMLSERIALIZE" => Some(Self::Xmlserialize),
+            "XMLTABLE" => Some(Self::Xmltable),
+            "YEAR_P" => Some(Self::YearP),
+            "YES_P" => Some(Self::YesP),
+            "ZONE" => Some(Self::Zone),
+            "FORMAT_LA" => Some(Self::FormatLa),
+            "NOT_LA" => Some(Self::NotLa),
+            "NULLS_LA" => Some(Self::NullsLa),
+            "WITH_LA" => Some(Self::WithLa),
+            "WITHOUT_LA" => Some(Self::WithoutLa),
+            "MODE_TYPE_NAME" => Some(Self::ModeTypeName),
+            "MODE_PLPGSQL_EXPR" => Some(Self::ModePlpgsqlExpr),
+            "MODE_PLPGSQL_ASSIGN1" => Some(Self::ModePlpgsqlAssign1),
+            "MODE_PLPGSQL_ASSIGN2" => Some(Self::ModePlpgsqlAssign2),
+            "MODE_PLPGSQL_ASSIGN3" => Some(Self::ModePlpgsqlAssign3),
+            "UMINUS" => Some(Self::Uminus),
+            _ => None,
+        }
+    }
+}
diff --git a/crates/pgt_query/src/scan.rs b/crates/pgt_query/src/scan.rs
new file mode 100644
index 000000000..b12061e7f
--- /dev/null
+++ b/crates/pgt_query/src/scan.rs
@@ -0,0 +1,33 @@
+use std::ffi::{CStr, CString};
+
+use crate::bindings::*;
+use crate::error::*;
+use crate::protobuf;
+
+use prost::Message;
+
+/// Scans (lexes) the given SQL statement into tokens.
+///
+/// # Example
+///
+/// ```rust
+/// let result = pgt_query::scan("SELECT * FROM contacts");
+/// assert!(result.is_ok());
+/// ```
+pub fn scan(sql: &str) -> Result<protobuf::ScanResult> {
+    let input = CString::new(sql)?;
+    let result = unsafe { pg_query_scan(input.as_ptr()) };
+    let scan_result = if !result.error.is_null() {
+        let message = unsafe { CStr::from_ptr((*result.error).message) }
+            .to_string_lossy()
+            .to_string();
+        Err(Error::Scan(message))
+    } else {
+        let data = unsafe {
+            std::slice::from_raw_parts(result.pbuf.data as *const u8, result.pbuf.len as usize)
+        };
+        protobuf::ScanResult::decode(data).map_err(Error::Decode)
+    };
+    unsafe { pg_query_free_scan_result(result) };
+    scan_result
+}
diff --git a/crates/pgt_query/src/split.rs b/crates/pgt_query/src/split.rs
new file mode 100644
index 000000000..abb95eb87
--- /dev/null
+++ b/crates/pgt_query/src/split.rs
@@ -0,0 +1,86 @@
+use std::ffi::{CStr, CString};
+
+use crate::bindings::*;
+use crate::error::*;
+
+/// Split a well-formed query into separate statements.
+///
+/// # Example
+///
+/// ```rust
+/// let query = r#"select /*;*/ 1; select "2;", (select 3);"#;
+/// let statements = pgt_query::split_with_parser(query).unwrap();
+/// assert_eq!(statements, vec!["select /*;*/ 1", r#" select "2;", (select 3)"#]);
+/// ```
+///
+/// However, `split_with_parser` will fail on malformed statements
+///
+/// ```rust
+/// let query = "select 1; this statement is not sql; select 2;";
+/// let result = pgt_query::split_with_parser(query);
+/// let err = r#"syntax error at or near "this""#;
+/// assert_eq!(result, Err(pgt_query::Error::Split(err.to_string())));
+/// ```
+pub fn split_with_parser(query: &str) -> Result<Vec<&str>> {
+    let input = CString::new(query)?;
+    let result = unsafe { pg_query_split_with_parser(input.as_ptr()) };
+    let split_result = if !result.error.is_null() {
+        let message = unsafe { CStr::from_ptr((*result.error).message) }
+            .to_string_lossy()
+            .to_string();
+        Err(Error::Split(message))
+    } else {
+        let n_stmts = result.n_stmts as usize;
+        let mut statements = Vec::with_capacity(n_stmts);
+        for offset in 0..n_stmts {
+            let split_stmt = unsafe { *result.stmts.add(offset).read() };
+            let start = split_stmt.stmt_location as usize;
+            let end = start + split_stmt.stmt_len as usize;
+            statements.push(&query[start..end]);
+            // not sure the start..end slice'll hold up for non-utf8 charsets
+        }
+        Ok(statements)
+    };
+    unsafe { pg_query_free_split_result(result) };
+    split_result
+}
+
+/// Split a potentially-malformed query into separate statements. Note that
+/// invalid tokens will be skipped
+/// ```rust
+/// let query = r#"select /*;*/ 1; asdf; select "2;", (select 3); asdf"#;
+/// let statements = pgt_query::split_with_scanner(query).unwrap();
+/// assert_eq!(statements, vec![
+///     "select /*;*/ 1",
+///     // skipped " asdf" since it was an invalid token
+///     r#" select "2;", (select 3)"#,
+/// ]);
+/// ```
+pub fn split_with_scanner(query: &str) -> Result<Vec<&str>> {
+    let input = CString::new(query)?;
+    let result = unsafe { pg_query_split_with_scanner(input.as_ptr()) };
+    let split_result = if !result.error.is_null() {
+        let message = unsafe { CStr::from_ptr((*result.error).message) }
+            .to_string_lossy()
+            .to_string();
+        Err(Error::Split(message))
+    } else {
+        // don't use result.stderr_buffer since it appears unused unless
+        // libpg_query is compiled with DEBUG defined.
+        let n_stmts = result.n_stmts as usize;
+        let mut start: usize;
+        let mut end: usize;
+        let mut statements = Vec::with_capacity(n_stmts);
+        for offset in 0..n_stmts {
+            let split_stmt = unsafe { *result.stmts.add(offset).read() };
+            start = split_stmt.stmt_location as usize;
+            // TODO: consider comparing the new value of start to the old value
+            // of end to see if any region larger than a statement-separator got skipped
+            end = start + split_stmt.stmt_len as usize;
+            statements.push(&query[start..end]);
+        }
+        Ok(statements)
+    };
+    unsafe { pg_query_free_split_result(result) };
+    split_result
+}
diff --git a/crates/pgt_query_ext/Cargo.toml b/crates/pgt_query_ext/Cargo.toml
index 3e6b57c17..9b4bfa1d3 100644
--- a/crates/pgt_query_ext/Cargo.toml
+++ b/crates/pgt_query_ext/Cargo.toml
@@ -12,10 +12,8 @@ version              = "0.0.0"
 
 
 [dependencies]
-petgraph = "0.6.4"
-
-pg_query.workspace        = true
 pgt_diagnostics.workspace = true
+pgt_query.workspace       = true
 pgt_text_size.workspace   = true
 
 [lib]
diff --git a/crates/pgt_query_ext/src/diagnostics.rs b/crates/pgt_query_ext/src/diagnostics.rs
index 1a068dc0a..4b5d92e9e 100644
--- a/crates/pgt_query_ext/src/diagnostics.rs
+++ b/crates/pgt_query_ext/src/diagnostics.rs
@@ -30,8 +30,8 @@ impl SyntaxDiagnostic {
     }
 }
 
-impl From<pg_query::Error> for SyntaxDiagnostic {
-    fn from(err: pg_query::Error) -> Self {
+impl From<pgt_query::Error> for SyntaxDiagnostic {
+    fn from(err: pgt_query::Error) -> Self {
         SyntaxDiagnostic {
             span: None,
             message: MessageAndDescription::from(err.to_string()),
diff --git a/crates/pgt_query_ext/src/lib.rs b/crates/pgt_query_ext/src/lib.rs
index 5882a7785..b0288da8d 100644
--- a/crates/pgt_query_ext/src/lib.rs
+++ b/crates/pgt_query_ext/src/lib.rs
@@ -1,62 +1,2 @@
-//! Postgres Statement Parser
-//!
-//! Simple wrapper crate for `pg_query` to expose types and a function to get the root node for an
-//! SQL statement.
-//!
-//! It also host any "extensions" to the `pg_query` crate that are not yet contributed upstream.
-//! Extensions include
-//! - `get_location` to get the location of a node
-//! - `get_node_properties` to get the properties of a node
-//! - `get_nodes` to get all the nodes in the AST as a petgraph tree
-//! - `ChildrenIterator` to iterate over the children of a node
 pub mod diagnostics;
-
-pub use pg_query::protobuf;
-pub use pg_query::{Error, NodeEnum, Result};
-
-pub fn parse(sql: &str) -> Result<NodeEnum> {
-    pg_query::parse(sql).map(|parsed| {
-        parsed
-            .protobuf
-            .nodes()
-            .iter()
-            .find(|n| n.1 == 1)
-            .map(|n| n.0.to_enum())
-            .ok_or_else(|| Error::Parse("Unable to find root node".to_string()))
-    })?
-}
-
-/// This function parses a PL/pgSQL function.
-///
-/// It expects the entire `CREATE FUNCTION` statement.
-pub fn parse_plpgsql(sql: &str) -> Result<()> {
-    // we swallow the error until we have a proper binding
-    let _ = pg_query::parse_plpgsql(sql)?;
-
-    Ok(())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_parse_plpgsql_err() {
-        let input = "
-create function test_organisation_id ()
-    returns setof text
-    language plpgsql
-    security invoker
-    as $$
-    -- syntax error here
-    decare
-        v_organisation_id uuid;
-begin
-    select 1;
-end
-$$;
-        ";
-
-        assert!(parse_plpgsql(input).is_err());
-    }
-}
+pub mod utils;
diff --git a/crates/pgt_query_ext/src/utils.rs b/crates/pgt_query_ext/src/utils.rs
new file mode 100644
index 000000000..6dedebea1
--- /dev/null
+++ b/crates/pgt_query_ext/src/utils.rs
@@ -0,0 +1,100 @@
+/// Helper function to find a specific option value from function options
+pub fn find_option_value(
+    create_fn: &pgt_query::protobuf::CreateFunctionStmt,
+    option_name: &str,
+) -> Option<String> {
+    create_fn
+        .options
+        .iter()
+        .filter_map(|opt_wrapper| opt_wrapper.node.as_ref())
+        .find_map(|opt| {
+            if let pgt_query::NodeEnum::DefElem(def_elem) = opt {
+                if def_elem.defname == option_name {
+                    def_elem
+                        .arg
+                        .iter()
+                        .filter_map(|arg_wrapper| arg_wrapper.node.as_ref())
+                        .find_map(|arg| {
+                            if let pgt_query::NodeEnum::String(s) = arg {
+                                Some(s.sval.clone())
+                            } else if let pgt_query::NodeEnum::List(l) = arg {
+                                l.items.iter().find_map(|item_wrapper| {
+                                    if let Some(pgt_query::NodeEnum::String(s)) =
+                                        item_wrapper.node.as_ref()
+                                    {
+                                        Some(s.sval.clone())
+                                    } else {
+                                        None
+                                    }
+                                })
+                            } else {
+                                None
+                            }
+                        })
+                } else {
+                    None
+                }
+            } else {
+                None
+            }
+        })
+}
+
+pub fn parse_name(nodes: &[pgt_query::protobuf::Node]) -> Option<(Option<String>, String)> {
+    let names = nodes
+        .iter()
+        .map(|n| match &n.node {
+            Some(pgt_query::NodeEnum::String(s)) => Some(s.sval.clone()),
+            _ => None,
+        })
+        .collect::<Vec<_>>();
+
+    match names.as_slice() {
+        [Some(schema), Some(name)] => Some((Some(schema.clone()), name.clone())),
+        [Some(name)] => Some((None, name.clone())),
+        _ => None,
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::utils::{find_option_value, parse_name};
+
+    #[test]
+    fn test_find_option_value() {
+        let input = "
+            CREATE OR REPLACE FUNCTION public.f1()
+            RETURNS boolean
+            LANGUAGE plpgsql
+            AS $function$
+            declare r t1 := (select t1 from t1 where a = 1);
+            BEGIN
+              if r.c is null or
+                 true is false
+                then -- there is bug - table t1 missing \"c\" column
+                RAISE NOTICE 'c is null';
+              end if;
+            END;
+            $function$;
+"
+        .trim();
+
+        let ast = pgt_query::parse(input).unwrap().into_root().unwrap();
+        let create_fn = match &ast {
+            pgt_query::NodeEnum::CreateFunctionStmt(stmt) => stmt,
+            _ => panic!("Expected CreateFunctionStmt"),
+        };
+
+        assert_eq!(
+            find_option_value(create_fn, "language"),
+            Some("plpgsql".to_string())
+        );
+
+        assert!(find_option_value(create_fn, "as").is_some(),);
+
+        assert_eq!(
+            parse_name(&create_fn.return_type.as_ref().unwrap().names),
+            Some((Some("pg_catalog".to_string()), "bool".to_string()))
+        );
+    }
+}
diff --git a/crates/pgt_query_macros/Cargo.toml b/crates/pgt_query_macros/Cargo.toml
new file mode 100644
index 000000000..0fcc52cf6
--- /dev/null
+++ b/crates/pgt_query_macros/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+authors.workspace    = true
+categories.workspace = true
+description          = "<DESCRIPTION>"
+edition.workspace    = true
+homepage.workspace   = true
+keywords.workspace   = true
+license.workspace    = true
+name                 = "pgt_query_macros"
+repository.workspace = true
+version              = "0.0.0"
+
+[dependencies]
+convert_case          = { workspace = true }
+proc-macro2.workspace = true
+prost-reflect         = { workspace = true }
+protox                = { workspace = true }
+quote.workspace       = true
+
+[lib]
+proc-macro = true
+
+[build-dependencies]
+ureq = "2.9"
diff --git a/crates/pgt_query_macros/build.rs b/crates/pgt_query_macros/build.rs
new file mode 100644
index 000000000..db83ce86e
--- /dev/null
+++ b/crates/pgt_query_macros/build.rs
@@ -0,0 +1,59 @@
+use std::env;
+use std::fs;
+use std::io::Write;
+use std::path::PathBuf;
+
+// This should match the version used by pgt_query crate
+// You can configure this via environment variable PG_QUERY_VERSION if needed
+static LIBPG_QUERY_TAG: &str = "17-6.1.0";
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    // Allow version override via environment variable
+    let version = env::var("PG_QUERY_VERSION").unwrap_or_else(|_| LIBPG_QUERY_TAG.to_string());
+
+    // Get the manifest directory (source directory)
+    let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
+    let postgres_dir = manifest_dir.join("postgres");
+    let proto_filename = format!("{}.proto", version);
+    let proto_path = postgres_dir.join(&proto_filename);
+
+    // Download proto file if not already present in source directory
+    if !proto_path.exists() {
+        println!(
+            "cargo:warning=Downloading pg_query.proto for libpg_query {} to source directory",
+            version
+        );
+
+        // Create postgres directory if it doesn't exist
+        fs::create_dir_all(&postgres_dir)?;
+
+        // Download the proto file
+        let proto_url = format!(
+            "https://raw.githubusercontent.com/pganalyze/libpg_query/{}/protobuf/pg_query.proto",
+            version
+        );
+
+        let response = ureq::get(&proto_url).call()?;
+        let proto_content = response.into_string()?;
+
+        // Write proto file to source directory
+        let mut file = fs::File::create(&proto_path)?;
+        file.write_all(proto_content.as_bytes())?;
+
+        println!(
+            "cargo:warning=Successfully downloaded pg_query.proto to {}",
+            proto_path.display()
+        );
+    }
+
+    // Set environment variable for the proc macro
+    println!(
+        "cargo:rustc-env=PG_QUERY_PROTO_PATH={}",
+        proto_path.display()
+    );
+
+    // Tell cargo to rerun if the proto file changes
+    println!("cargo:rerun-if-changed={}", proto_path.display());
+
+    Ok(())
+}
diff --git a/crates/pgt_query_macros/postgres/17-6.1.0.proto b/crates/pgt_query_macros/postgres/17-6.1.0.proto
new file mode 100644
index 000000000..24a8f14cd
--- /dev/null
+++ b/crates/pgt_query_macros/postgres/17-6.1.0.proto
@@ -0,0 +1,4110 @@
+// This file is autogenerated by ./scripts/generate_protobuf_and_funcs.rb
+
+syntax = "proto3";
+
+package pg_query;
+
+message ParseResult {
+  int32 version = 1;
+  repeated RawStmt stmts = 2;
+}
+
+message ScanResult {
+  int32 version = 1;
+  repeated ScanToken tokens = 2;
+}
+
+message Node {
+  oneof node {
+		Alias alias = 1 [json_name="Alias"];
+    RangeVar range_var = 2 [json_name="RangeVar"];
+    TableFunc table_func = 3 [json_name="TableFunc"];
+    IntoClause into_clause = 4 [json_name="IntoClause"];
+    Var var = 5 [json_name="Var"];
+    Param param = 6 [json_name="Param"];
+    Aggref aggref = 7 [json_name="Aggref"];
+    GroupingFunc grouping_func = 8 [json_name="GroupingFunc"];
+    WindowFunc window_func = 9 [json_name="WindowFunc"];
+    WindowFuncRunCondition window_func_run_condition = 10 [json_name="WindowFuncRunCondition"];
+    MergeSupportFunc merge_support_func = 11 [json_name="MergeSupportFunc"];
+    SubscriptingRef subscripting_ref = 12 [json_name="SubscriptingRef"];
+    FuncExpr func_expr = 13 [json_name="FuncExpr"];
+    NamedArgExpr named_arg_expr = 14 [json_name="NamedArgExpr"];
+    OpExpr op_expr = 15 [json_name="OpExpr"];
+    DistinctExpr distinct_expr = 16 [json_name="DistinctExpr"];
+    NullIfExpr null_if_expr = 17 [json_name="NullIfExpr"];
+    ScalarArrayOpExpr scalar_array_op_expr = 18 [json_name="ScalarArrayOpExpr"];
+    BoolExpr bool_expr = 19 [json_name="BoolExpr"];
+    SubLink sub_link = 20 [json_name="SubLink"];
+    SubPlan sub_plan = 21 [json_name="SubPlan"];
+    AlternativeSubPlan alternative_sub_plan = 22 [json_name="AlternativeSubPlan"];
+    FieldSelect field_select = 23 [json_name="FieldSelect"];
+    FieldStore field_store = 24 [json_name="FieldStore"];
+    RelabelType relabel_type = 25 [json_name="RelabelType"];
+    CoerceViaIO coerce_via_io = 26 [json_name="CoerceViaIO"];
+    ArrayCoerceExpr array_coerce_expr = 27 [json_name="ArrayCoerceExpr"];
+    ConvertRowtypeExpr convert_rowtype_expr = 28 [json_name="ConvertRowtypeExpr"];
+    CollateExpr collate_expr = 29 [json_name="CollateExpr"];
+    CaseExpr case_expr = 30 [json_name="CaseExpr"];
+    CaseWhen case_when = 31 [json_name="CaseWhen"];
+    CaseTestExpr case_test_expr = 32 [json_name="CaseTestExpr"];
+    ArrayExpr array_expr = 33 [json_name="ArrayExpr"];
+    RowExpr row_expr = 34 [json_name="RowExpr"];
+    RowCompareExpr row_compare_expr = 35 [json_name="RowCompareExpr"];
+    CoalesceExpr coalesce_expr = 36 [json_name="CoalesceExpr"];
+    MinMaxExpr min_max_expr = 37 [json_name="MinMaxExpr"];
+    SQLValueFunction sqlvalue_function = 38 [json_name="SQLValueFunction"];
+    XmlExpr xml_expr = 39 [json_name="XmlExpr"];
+    JsonFormat json_format = 40 [json_name="JsonFormat"];
+    JsonReturning json_returning = 41 [json_name="JsonReturning"];
+    JsonValueExpr json_value_expr = 42 [json_name="JsonValueExpr"];
+    JsonConstructorExpr json_constructor_expr = 43 [json_name="JsonConstructorExpr"];
+    JsonIsPredicate json_is_predicate = 44 [json_name="JsonIsPredicate"];
+    JsonBehavior json_behavior = 45 [json_name="JsonBehavior"];
+    JsonExpr json_expr = 46 [json_name="JsonExpr"];
+    JsonTablePath json_table_path = 47 [json_name="JsonTablePath"];
+    JsonTablePathScan json_table_path_scan = 48 [json_name="JsonTablePathScan"];
+    JsonTableSiblingJoin json_table_sibling_join = 49 [json_name="JsonTableSiblingJoin"];
+    NullTest null_test = 50 [json_name="NullTest"];
+    BooleanTest boolean_test = 51 [json_name="BooleanTest"];
+    MergeAction merge_action = 52 [json_name="MergeAction"];
+    CoerceToDomain coerce_to_domain = 53 [json_name="CoerceToDomain"];
+    CoerceToDomainValue coerce_to_domain_value = 54 [json_name="CoerceToDomainValue"];
+    SetToDefault set_to_default = 55 [json_name="SetToDefault"];
+    CurrentOfExpr current_of_expr = 56 [json_name="CurrentOfExpr"];
+    NextValueExpr next_value_expr = 57 [json_name="NextValueExpr"];
+    InferenceElem inference_elem = 58 [json_name="InferenceElem"];
+    TargetEntry target_entry = 59 [json_name="TargetEntry"];
+    RangeTblRef range_tbl_ref = 60 [json_name="RangeTblRef"];
+    JoinExpr join_expr = 61 [json_name="JoinExpr"];
+    FromExpr from_expr = 62 [json_name="FromExpr"];
+    OnConflictExpr on_conflict_expr = 63 [json_name="OnConflictExpr"];
+    Query query = 64 [json_name="Query"];
+    TypeName type_name = 65 [json_name="TypeName"];
+    ColumnRef column_ref = 66 [json_name="ColumnRef"];
+    ParamRef param_ref = 67 [json_name="ParamRef"];
+    A_Expr a_expr = 68 [json_name="A_Expr"];
+    TypeCast type_cast = 69 [json_name="TypeCast"];
+    CollateClause collate_clause = 70 [json_name="CollateClause"];
+    RoleSpec role_spec = 71 [json_name="RoleSpec"];
+    FuncCall func_call = 72 [json_name="FuncCall"];
+    A_Star a_star = 73 [json_name="A_Star"];
+    A_Indices a_indices = 74 [json_name="A_Indices"];
+    A_Indirection a_indirection = 75 [json_name="A_Indirection"];
+    A_ArrayExpr a_array_expr = 76 [json_name="A_ArrayExpr"];
+    ResTarget res_target = 77 [json_name="ResTarget"];
+    MultiAssignRef multi_assign_ref = 78 [json_name="MultiAssignRef"];
+    SortBy sort_by = 79 [json_name="SortBy"];
+    WindowDef window_def = 80 [json_name="WindowDef"];
+    RangeSubselect range_subselect = 81 [json_name="RangeSubselect"];
+    RangeFunction range_function = 82 [json_name="RangeFunction"];
+    RangeTableFunc range_table_func = 83 [json_name="RangeTableFunc"];
+    RangeTableFuncCol range_table_func_col = 84 [json_name="RangeTableFuncCol"];
+    RangeTableSample range_table_sample = 85 [json_name="RangeTableSample"];
+    ColumnDef column_def = 86 [json_name="ColumnDef"];
+    TableLikeClause table_like_clause = 87 [json_name="TableLikeClause"];
+    IndexElem index_elem = 88 [json_name="IndexElem"];
+    DefElem def_elem = 89 [json_name="DefElem"];
+    LockingClause locking_clause = 90 [json_name="LockingClause"];
+    XmlSerialize xml_serialize = 91 [json_name="XmlSerialize"];
+    PartitionElem partition_elem = 92 [json_name="PartitionElem"];
+    PartitionSpec partition_spec = 93 [json_name="PartitionSpec"];
+    PartitionBoundSpec partition_bound_spec = 94 [json_name="PartitionBoundSpec"];
+    PartitionRangeDatum partition_range_datum = 95 [json_name="PartitionRangeDatum"];
+    SinglePartitionSpec single_partition_spec = 96 [json_name="SinglePartitionSpec"];
+    PartitionCmd partition_cmd = 97 [json_name="PartitionCmd"];
+    RangeTblEntry range_tbl_entry = 98 [json_name="RangeTblEntry"];
+    RTEPermissionInfo rtepermission_info = 99 [json_name="RTEPermissionInfo"];
+    RangeTblFunction range_tbl_function = 100 [json_name="RangeTblFunction"];
+    TableSampleClause table_sample_clause = 101 [json_name="TableSampleClause"];
+    WithCheckOption with_check_option = 102 [json_name="WithCheckOption"];
+    SortGroupClause sort_group_clause = 103 [json_name="SortGroupClause"];
+    GroupingSet grouping_set = 104 [json_name="GroupingSet"];
+    WindowClause window_clause = 105 [json_name="WindowClause"];
+    RowMarkClause row_mark_clause = 106 [json_name="RowMarkClause"];
+    WithClause with_clause = 107 [json_name="WithClause"];
+    InferClause infer_clause = 108 [json_name="InferClause"];
+    OnConflictClause on_conflict_clause = 109 [json_name="OnConflictClause"];
+    CTESearchClause ctesearch_clause = 110 [json_name="CTESearchClause"];
+    CTECycleClause ctecycle_clause = 111 [json_name="CTECycleClause"];
+    CommonTableExpr common_table_expr = 112 [json_name="CommonTableExpr"];
+    MergeWhenClause merge_when_clause = 113 [json_name="MergeWhenClause"];
+    TriggerTransition trigger_transition = 114 [json_name="TriggerTransition"];
+    JsonOutput json_output = 115 [json_name="JsonOutput"];
+    JsonArgument json_argument = 116 [json_name="JsonArgument"];
+    JsonFuncExpr json_func_expr = 117 [json_name="JsonFuncExpr"];
+    JsonTablePathSpec json_table_path_spec = 118 [json_name="JsonTablePathSpec"];
+    JsonTable json_table = 119 [json_name="JsonTable"];
+    JsonTableColumn json_table_column = 120 [json_name="JsonTableColumn"];
+    JsonKeyValue json_key_value = 121 [json_name="JsonKeyValue"];
+    JsonParseExpr json_parse_expr = 122 [json_name="JsonParseExpr"];
+    JsonScalarExpr json_scalar_expr = 123 [json_name="JsonScalarExpr"];
+    JsonSerializeExpr json_serialize_expr = 124 [json_name="JsonSerializeExpr"];
+    JsonObjectConstructor json_object_constructor = 125 [json_name="JsonObjectConstructor"];
+    JsonArrayConstructor json_array_constructor = 126 [json_name="JsonArrayConstructor"];
+    JsonArrayQueryConstructor json_array_query_constructor = 127 [json_name="JsonArrayQueryConstructor"];
+    JsonAggConstructor json_agg_constructor = 128 [json_name="JsonAggConstructor"];
+    JsonObjectAgg json_object_agg = 129 [json_name="JsonObjectAgg"];
+    JsonArrayAgg json_array_agg = 130 [json_name="JsonArrayAgg"];
+    RawStmt raw_stmt = 131 [json_name="RawStmt"];
+    InsertStmt insert_stmt = 132 [json_name="InsertStmt"];
+    DeleteStmt delete_stmt = 133 [json_name="DeleteStmt"];
+    UpdateStmt update_stmt = 134 [json_name="UpdateStmt"];
+    MergeStmt merge_stmt = 135 [json_name="MergeStmt"];
+    SelectStmt select_stmt = 136 [json_name="SelectStmt"];
+    SetOperationStmt set_operation_stmt = 137 [json_name="SetOperationStmt"];
+    ReturnStmt return_stmt = 138 [json_name="ReturnStmt"];
+    PLAssignStmt plassign_stmt = 139 [json_name="PLAssignStmt"];
+    CreateSchemaStmt create_schema_stmt = 140 [json_name="CreateSchemaStmt"];
+    AlterTableStmt alter_table_stmt = 141 [json_name="AlterTableStmt"];
+    ReplicaIdentityStmt replica_identity_stmt = 142 [json_name="ReplicaIdentityStmt"];
+    AlterTableCmd alter_table_cmd = 143 [json_name="AlterTableCmd"];
+    AlterCollationStmt alter_collation_stmt = 144 [json_name="AlterCollationStmt"];
+    AlterDomainStmt alter_domain_stmt = 145 [json_name="AlterDomainStmt"];
+    GrantStmt grant_stmt = 146 [json_name="GrantStmt"];
+    ObjectWithArgs object_with_args = 147 [json_name="ObjectWithArgs"];
+    AccessPriv access_priv = 148 [json_name="AccessPriv"];
+    GrantRoleStmt grant_role_stmt = 149 [json_name="GrantRoleStmt"];
+    AlterDefaultPrivilegesStmt alter_default_privileges_stmt = 150 [json_name="AlterDefaultPrivilegesStmt"];
+    CopyStmt copy_stmt = 151 [json_name="CopyStmt"];
+    VariableSetStmt variable_set_stmt = 152 [json_name="VariableSetStmt"];
+    VariableShowStmt variable_show_stmt = 153 [json_name="VariableShowStmt"];
+    CreateStmt create_stmt = 154 [json_name="CreateStmt"];
+    Constraint constraint = 155 [json_name="Constraint"];
+    CreateTableSpaceStmt create_table_space_stmt = 156 [json_name="CreateTableSpaceStmt"];
+    DropTableSpaceStmt drop_table_space_stmt = 157 [json_name="DropTableSpaceStmt"];
+    AlterTableSpaceOptionsStmt alter_table_space_options_stmt = 158 [json_name="AlterTableSpaceOptionsStmt"];
+    AlterTableMoveAllStmt alter_table_move_all_stmt = 159 [json_name="AlterTableMoveAllStmt"];
+    CreateExtensionStmt create_extension_stmt = 160 [json_name="CreateExtensionStmt"];
+    AlterExtensionStmt alter_extension_stmt = 161 [json_name="AlterExtensionStmt"];
+    AlterExtensionContentsStmt alter_extension_contents_stmt = 162 [json_name="AlterExtensionContentsStmt"];
+    CreateFdwStmt create_fdw_stmt = 163 [json_name="CreateFdwStmt"];
+    AlterFdwStmt alter_fdw_stmt = 164 [json_name="AlterFdwStmt"];
+    CreateForeignServerStmt create_foreign_server_stmt = 165 [json_name="CreateForeignServerStmt"];
+    AlterForeignServerStmt alter_foreign_server_stmt = 166 [json_name="AlterForeignServerStmt"];
+    CreateForeignTableStmt create_foreign_table_stmt = 167 [json_name="CreateForeignTableStmt"];
+    CreateUserMappingStmt create_user_mapping_stmt = 168 [json_name="CreateUserMappingStmt"];
+    AlterUserMappingStmt alter_user_mapping_stmt = 169 [json_name="AlterUserMappingStmt"];
+    DropUserMappingStmt drop_user_mapping_stmt = 170 [json_name="DropUserMappingStmt"];
+    ImportForeignSchemaStmt import_foreign_schema_stmt = 171 [json_name="ImportForeignSchemaStmt"];
+    CreatePolicyStmt create_policy_stmt = 172 [json_name="CreatePolicyStmt"];
+    AlterPolicyStmt alter_policy_stmt = 173 [json_name="AlterPolicyStmt"];
+    CreateAmStmt create_am_stmt = 174 [json_name="CreateAmStmt"];
+    CreateTrigStmt create_trig_stmt = 175 [json_name="CreateTrigStmt"];
+    CreateEventTrigStmt create_event_trig_stmt = 176 [json_name="CreateEventTrigStmt"];
+    AlterEventTrigStmt alter_event_trig_stmt = 177 [json_name="AlterEventTrigStmt"];
+    CreatePLangStmt create_plang_stmt = 178 [json_name="CreatePLangStmt"];
+    CreateRoleStmt create_role_stmt = 179 [json_name="CreateRoleStmt"];
+    AlterRoleStmt alter_role_stmt = 180 [json_name="AlterRoleStmt"];
+    AlterRoleSetStmt alter_role_set_stmt = 181 [json_name="AlterRoleSetStmt"];
+    DropRoleStmt drop_role_stmt = 182 [json_name="DropRoleStmt"];
+    CreateSeqStmt create_seq_stmt = 183 [json_name="CreateSeqStmt"];
+    AlterSeqStmt alter_seq_stmt = 184 [json_name="AlterSeqStmt"];
+    DefineStmt define_stmt = 185 [json_name="DefineStmt"];
+    CreateDomainStmt create_domain_stmt = 186 [json_name="CreateDomainStmt"];
+    CreateOpClassStmt create_op_class_stmt = 187 [json_name="CreateOpClassStmt"];
+    CreateOpClassItem create_op_class_item = 188 [json_name="CreateOpClassItem"];
+    CreateOpFamilyStmt create_op_family_stmt = 189 [json_name="CreateOpFamilyStmt"];
+    AlterOpFamilyStmt alter_op_family_stmt = 190 [json_name="AlterOpFamilyStmt"];
+    DropStmt drop_stmt = 191 [json_name="DropStmt"];
+    TruncateStmt truncate_stmt = 192 [json_name="TruncateStmt"];
+    CommentStmt comment_stmt = 193 [json_name="CommentStmt"];
+    SecLabelStmt sec_label_stmt = 194 [json_name="SecLabelStmt"];
+    DeclareCursorStmt declare_cursor_stmt = 195 [json_name="DeclareCursorStmt"];
+    ClosePortalStmt close_portal_stmt = 196 [json_name="ClosePortalStmt"];
+    FetchStmt fetch_stmt = 197 [json_name="FetchStmt"];
+    IndexStmt index_stmt = 198 [json_name="IndexStmt"];
+    CreateStatsStmt create_stats_stmt = 199 [json_name="CreateStatsStmt"];
+    StatsElem stats_elem = 200 [json_name="StatsElem"];
+    AlterStatsStmt alter_stats_stmt = 201 [json_name="AlterStatsStmt"];
+    CreateFunctionStmt create_function_stmt = 202 [json_name="CreateFunctionStmt"];
+    FunctionParameter function_parameter = 203 [json_name="FunctionParameter"];
+    AlterFunctionStmt alter_function_stmt = 204 [json_name="AlterFunctionStmt"];
+    DoStmt do_stmt = 205 [json_name="DoStmt"];
+    InlineCodeBlock inline_code_block = 206 [json_name="InlineCodeBlock"];
+    CallStmt call_stmt = 207 [json_name="CallStmt"];
+    CallContext call_context = 208 [json_name="CallContext"];
+    RenameStmt rename_stmt = 209 [json_name="RenameStmt"];
+    AlterObjectDependsStmt alter_object_depends_stmt = 210 [json_name="AlterObjectDependsStmt"];
+    AlterObjectSchemaStmt alter_object_schema_stmt = 211 [json_name="AlterObjectSchemaStmt"];
+    AlterOwnerStmt alter_owner_stmt = 212 [json_name="AlterOwnerStmt"];
+    AlterOperatorStmt alter_operator_stmt = 213 [json_name="AlterOperatorStmt"];
+    AlterTypeStmt alter_type_stmt = 214 [json_name="AlterTypeStmt"];
+    RuleStmt rule_stmt = 215 [json_name="RuleStmt"];
+    NotifyStmt notify_stmt = 216 [json_name="NotifyStmt"];
+    ListenStmt listen_stmt = 217 [json_name="ListenStmt"];
+    UnlistenStmt unlisten_stmt = 218 [json_name="UnlistenStmt"];
+    TransactionStmt transaction_stmt = 219 [json_name="TransactionStmt"];
+    CompositeTypeStmt composite_type_stmt = 220 [json_name="CompositeTypeStmt"];
+    CreateEnumStmt create_enum_stmt = 221 [json_name="CreateEnumStmt"];
+    CreateRangeStmt create_range_stmt = 222 [json_name="CreateRangeStmt"];
+    AlterEnumStmt alter_enum_stmt = 223 [json_name="AlterEnumStmt"];
+    ViewStmt view_stmt = 224 [json_name="ViewStmt"];
+    LoadStmt load_stmt = 225 [json_name="LoadStmt"];
+    CreatedbStmt createdb_stmt = 226 [json_name="CreatedbStmt"];
+    AlterDatabaseStmt alter_database_stmt = 227 [json_name="AlterDatabaseStmt"];
+    AlterDatabaseRefreshCollStmt alter_database_refresh_coll_stmt = 228 [json_name="AlterDatabaseRefreshCollStmt"];
+    AlterDatabaseSetStmt alter_database_set_stmt = 229 [json_name="AlterDatabaseSetStmt"];
+    DropdbStmt dropdb_stmt = 230 [json_name="DropdbStmt"];
+    AlterSystemStmt alter_system_stmt = 231 [json_name="AlterSystemStmt"];
+    ClusterStmt cluster_stmt = 232 [json_name="ClusterStmt"];
+    VacuumStmt vacuum_stmt = 233 [json_name="VacuumStmt"];
+    VacuumRelation vacuum_relation = 234 [json_name="VacuumRelation"];
+    ExplainStmt explain_stmt = 235 [json_name="ExplainStmt"];
+    CreateTableAsStmt create_table_as_stmt = 236 [json_name="CreateTableAsStmt"];
+    RefreshMatViewStmt refresh_mat_view_stmt = 237 [json_name="RefreshMatViewStmt"];
+    CheckPointStmt check_point_stmt = 238 [json_name="CheckPointStmt"];
+    DiscardStmt discard_stmt = 239 [json_name="DiscardStmt"];
+    LockStmt lock_stmt = 240 [json_name="LockStmt"];
+    ConstraintsSetStmt constraints_set_stmt = 241 [json_name="ConstraintsSetStmt"];
+    ReindexStmt reindex_stmt = 242 [json_name="ReindexStmt"];
+    CreateConversionStmt create_conversion_stmt = 243 [json_name="CreateConversionStmt"];
+    CreateCastStmt create_cast_stmt = 244 [json_name="CreateCastStmt"];
+    CreateTransformStmt create_transform_stmt = 245 [json_name="CreateTransformStmt"];
+    PrepareStmt prepare_stmt = 246 [json_name="PrepareStmt"];
+    ExecuteStmt execute_stmt = 247 [json_name="ExecuteStmt"];
+    DeallocateStmt deallocate_stmt = 248 [json_name="DeallocateStmt"];
+    DropOwnedStmt drop_owned_stmt = 249 [json_name="DropOwnedStmt"];
+    ReassignOwnedStmt reassign_owned_stmt = 250 [json_name="ReassignOwnedStmt"];
+    AlterTSDictionaryStmt alter_tsdictionary_stmt = 251 [json_name="AlterTSDictionaryStmt"];
+    AlterTSConfigurationStmt alter_tsconfiguration_stmt = 252 [json_name="AlterTSConfigurationStmt"];
+    PublicationTable publication_table = 253 [json_name="PublicationTable"];
+    PublicationObjSpec publication_obj_spec = 254 [json_name="PublicationObjSpec"];
+    CreatePublicationStmt create_publication_stmt = 255 [json_name="CreatePublicationStmt"];
+    AlterPublicationStmt alter_publication_stmt = 256 [json_name="AlterPublicationStmt"];
+    CreateSubscriptionStmt create_subscription_stmt = 257 [json_name="CreateSubscriptionStmt"];
+    AlterSubscriptionStmt alter_subscription_stmt = 258 [json_name="AlterSubscriptionStmt"];
+    DropSubscriptionStmt drop_subscription_stmt = 259 [json_name="DropSubscriptionStmt"];
+    Integer integer = 260 [json_name="Integer"];
+    Float float = 261 [json_name="Float"];
+    Boolean boolean = 262 [json_name="Boolean"];
+    String string = 263 [json_name="String"];
+    BitString bit_string = 264 [json_name="BitString"];
+    List list = 265 [json_name="List"];
+    IntList int_list = 266 [json_name="IntList"];
+    OidList oid_list = 267 [json_name="OidList"];
+    A_Const a_const = 268 [json_name="A_Const"];
+  }
+}
+
+message Integer
+{
+  int32 ival = 1; /* machine integer */
+}
+
+message Float
+{
+  string fval = 1; /* string */
+}
+
+message Boolean
+{
+  bool boolval = 1;
+}
+
+message String
+{
+  string sval = 1; /* string */
+}
+
+message BitString
+{
+  string bsval = 1; /* string */
+}
+
+message List
+{
+  repeated Node items = 1;
+}
+
+message OidList
+{
+  repeated Node items = 1;
+}
+
+message IntList
+{
+  repeated Node items = 1;
+}
+
+message A_Const
+{
+  oneof val {
+    Integer ival = 1;
+    Float fval = 2;
+    Boolean boolval = 3;
+    String sval = 4;
+    BitString bsval = 5;
+  }
+  bool isnull = 10;
+  int32 location = 11;
+}
+
+message Alias
+{
+  string aliasname = 1 [json_name="aliasname"];
+  repeated Node colnames = 2 [json_name="colnames"];
+}
+
+message RangeVar
+{
+  string catalogname = 1 [json_name="catalogname"];
+  string schemaname = 2 [json_name="schemaname"];
+  string relname = 3 [json_name="relname"];
+  bool inh = 4 [json_name="inh"];
+  string relpersistence = 5 [json_name="relpersistence"];
+  Alias alias = 6 [json_name="alias"];
+  int32 location = 7 [json_name="location"];
+}
+
+message TableFunc
+{
+  TableFuncType functype = 1 [json_name="functype"];
+  repeated Node ns_uris = 2 [json_name="ns_uris"];
+  repeated Node ns_names = 3 [json_name="ns_names"];
+  Node docexpr = 4 [json_name="docexpr"];
+  Node rowexpr = 5 [json_name="rowexpr"];
+  repeated Node colnames = 6 [json_name="colnames"];
+  repeated Node coltypes = 7 [json_name="coltypes"];
+  repeated Node coltypmods = 8 [json_name="coltypmods"];
+  repeated Node colcollations = 9 [json_name="colcollations"];
+  repeated Node colexprs = 10 [json_name="colexprs"];
+  repeated Node coldefexprs = 11 [json_name="coldefexprs"];
+  repeated Node colvalexprs = 12 [json_name="colvalexprs"];
+  repeated Node passingvalexprs = 13 [json_name="passingvalexprs"];
+  repeated uint64 notnulls = 14 [json_name="notnulls"];
+  Node plan = 15 [json_name="plan"];
+  int32 ordinalitycol = 16 [json_name="ordinalitycol"];
+  int32 location = 17 [json_name="location"];
+}
+
+message IntoClause
+{
+  RangeVar rel = 1 [json_name="rel"];
+  repeated Node col_names = 2 [json_name="colNames"];
+  string access_method = 3 [json_name="accessMethod"];
+  repeated Node options = 4 [json_name="options"];
+  OnCommitAction on_commit = 5 [json_name="onCommit"];
+  string table_space_name = 6 [json_name="tableSpaceName"];
+  Node view_query = 7 [json_name="viewQuery"];
+  bool skip_data = 8 [json_name="skipData"];
+}
+
+message Var
+{
+  Node xpr = 1 [json_name="xpr"];
+  int32 varno = 2 [json_name="varno"];
+  int32 varattno = 3 [json_name="varattno"];
+  uint32 vartype = 4 [json_name="vartype"];
+  int32 vartypmod = 5 [json_name="vartypmod"];
+  uint32 varcollid = 6 [json_name="varcollid"];
+  repeated uint64 varnullingrels = 7 [json_name="varnullingrels"];
+  uint32 varlevelsup = 8 [json_name="varlevelsup"];
+  int32 location = 9 [json_name="location"];
+}
+
+message Param
+{
+  Node xpr = 1 [json_name="xpr"];
+  ParamKind paramkind = 2 [json_name="paramkind"];
+  int32 paramid = 3 [json_name="paramid"];
+  uint32 paramtype = 4 [json_name="paramtype"];
+  int32 paramtypmod = 5 [json_name="paramtypmod"];
+  uint32 paramcollid = 6 [json_name="paramcollid"];
+  int32 location = 7 [json_name="location"];
+}
+
+message Aggref
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 aggfnoid = 2 [json_name="aggfnoid"];
+  uint32 aggtype = 3 [json_name="aggtype"];
+  uint32 aggcollid = 4 [json_name="aggcollid"];
+  uint32 inputcollid = 5 [json_name="inputcollid"];
+  repeated Node aggargtypes = 6 [json_name="aggargtypes"];
+  repeated Node aggdirectargs = 7 [json_name="aggdirectargs"];
+  repeated Node args = 8 [json_name="args"];
+  repeated Node aggorder = 9 [json_name="aggorder"];
+  repeated Node aggdistinct = 10 [json_name="aggdistinct"];
+  Node aggfilter = 11 [json_name="aggfilter"];
+  bool aggstar = 12 [json_name="aggstar"];
+  bool aggvariadic = 13 [json_name="aggvariadic"];
+  string aggkind = 14 [json_name="aggkind"];
+  uint32 agglevelsup = 15 [json_name="agglevelsup"];
+  AggSplit aggsplit = 16 [json_name="aggsplit"];
+  int32 aggno = 17 [json_name="aggno"];
+  int32 aggtransno = 18 [json_name="aggtransno"];
+  int32 location = 19 [json_name="location"];
+}
+
+message GroupingFunc
+{
+  Node xpr = 1 [json_name="xpr"];
+  repeated Node args = 2 [json_name="args"];
+  repeated Node refs = 3 [json_name="refs"];
+  uint32 agglevelsup = 4 [json_name="agglevelsup"];
+  int32 location = 5 [json_name="location"];
+}
+
+message WindowFunc
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 winfnoid = 2 [json_name="winfnoid"];
+  uint32 wintype = 3 [json_name="wintype"];
+  uint32 wincollid = 4 [json_name="wincollid"];
+  uint32 inputcollid = 5 [json_name="inputcollid"];
+  repeated Node args = 6 [json_name="args"];
+  Node aggfilter = 7 [json_name="aggfilter"];
+  repeated Node run_condition = 8 [json_name="runCondition"];
+  uint32 winref = 9 [json_name="winref"];
+  bool winstar = 10 [json_name="winstar"];
+  bool winagg = 11 [json_name="winagg"];
+  int32 location = 12 [json_name="location"];
+}
+
+message WindowFuncRunCondition
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 opno = 2 [json_name="opno"];
+  uint32 inputcollid = 3 [json_name="inputcollid"];
+  bool wfunc_left = 4 [json_name="wfunc_left"];
+  Node arg = 5 [json_name="arg"];
+}
+
+message MergeSupportFunc
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 msftype = 2 [json_name="msftype"];
+  uint32 msfcollid = 3 [json_name="msfcollid"];
+  int32 location = 4 [json_name="location"];
+}
+
+message SubscriptingRef
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 refcontainertype = 2 [json_name="refcontainertype"];
+  uint32 refelemtype = 3 [json_name="refelemtype"];
+  uint32 refrestype = 4 [json_name="refrestype"];
+  int32 reftypmod = 5 [json_name="reftypmod"];
+  uint32 refcollid = 6 [json_name="refcollid"];
+  repeated Node refupperindexpr = 7 [json_name="refupperindexpr"];
+  repeated Node reflowerindexpr = 8 [json_name="reflowerindexpr"];
+  Node refexpr = 9 [json_name="refexpr"];
+  Node refassgnexpr = 10 [json_name="refassgnexpr"];
+}
+
+message FuncExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 funcid = 2 [json_name="funcid"];
+  uint32 funcresulttype = 3 [json_name="funcresulttype"];
+  bool funcretset = 4 [json_name="funcretset"];
+  bool funcvariadic = 5 [json_name="funcvariadic"];
+  CoercionForm funcformat = 6 [json_name="funcformat"];
+  uint32 funccollid = 7 [json_name="funccollid"];
+  uint32 inputcollid = 8 [json_name="inputcollid"];
+  repeated Node args = 9 [json_name="args"];
+  int32 location = 10 [json_name="location"];
+}
+
+message NamedArgExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  string name = 3 [json_name="name"];
+  int32 argnumber = 4 [json_name="argnumber"];
+  int32 location = 5 [json_name="location"];
+}
+
+message OpExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 opno = 2 [json_name="opno"];
+  uint32 opresulttype = 3 [json_name="opresulttype"];
+  bool opretset = 4 [json_name="opretset"];
+  uint32 opcollid = 5 [json_name="opcollid"];
+  uint32 inputcollid = 6 [json_name="inputcollid"];
+  repeated Node args = 7 [json_name="args"];
+  int32 location = 8 [json_name="location"];
+}
+
+message DistinctExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 opno = 2 [json_name="opno"];
+  uint32 opresulttype = 3 [json_name="opresulttype"];
+  bool opretset = 4 [json_name="opretset"];
+  uint32 opcollid = 5 [json_name="opcollid"];
+  uint32 inputcollid = 6 [json_name="inputcollid"];
+  repeated Node args = 7 [json_name="args"];
+  int32 location = 8 [json_name="location"];
+}
+
+message NullIfExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 opno = 2 [json_name="opno"];
+  uint32 opresulttype = 3 [json_name="opresulttype"];
+  bool opretset = 4 [json_name="opretset"];
+  uint32 opcollid = 5 [json_name="opcollid"];
+  uint32 inputcollid = 6 [json_name="inputcollid"];
+  repeated Node args = 7 [json_name="args"];
+  int32 location = 8 [json_name="location"];
+}
+
+message ScalarArrayOpExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 opno = 2 [json_name="opno"];
+  bool use_or = 3 [json_name="useOr"];
+  uint32 inputcollid = 4 [json_name="inputcollid"];
+  repeated Node args = 5 [json_name="args"];
+  int32 location = 6 [json_name="location"];
+}
+
+message BoolExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  BoolExprType boolop = 2 [json_name="boolop"];
+  repeated Node args = 3 [json_name="args"];
+  int32 location = 4 [json_name="location"];
+}
+
+message SubLink
+{
+  Node xpr = 1 [json_name="xpr"];
+  SubLinkType sub_link_type = 2 [json_name="subLinkType"];
+  int32 sub_link_id = 3 [json_name="subLinkId"];
+  Node testexpr = 4 [json_name="testexpr"];
+  repeated Node oper_name = 5 [json_name="operName"];
+  Node subselect = 6 [json_name="subselect"];
+  int32 location = 7 [json_name="location"];
+}
+
+message SubPlan
+{
+  Node xpr = 1 [json_name="xpr"];
+  SubLinkType sub_link_type = 2 [json_name="subLinkType"];
+  Node testexpr = 3 [json_name="testexpr"];
+  repeated Node param_ids = 4 [json_name="paramIds"];
+  int32 plan_id = 5 [json_name="plan_id"];
+  string plan_name = 6 [json_name="plan_name"];
+  uint32 first_col_type = 7 [json_name="firstColType"];
+  int32 first_col_typmod = 8 [json_name="firstColTypmod"];
+  uint32 first_col_collation = 9 [json_name="firstColCollation"];
+  bool use_hash_table = 10 [json_name="useHashTable"];
+  bool unknown_eq_false = 11 [json_name="unknownEqFalse"];
+  bool parallel_safe = 12 [json_name="parallel_safe"];
+  repeated Node set_param = 13 [json_name="setParam"];
+  repeated Node par_param = 14 [json_name="parParam"];
+  repeated Node args = 15 [json_name="args"];
+  double startup_cost = 16 [json_name="startup_cost"];
+  double per_call_cost = 17 [json_name="per_call_cost"];
+}
+
+message AlternativeSubPlan
+{
+  Node xpr = 1 [json_name="xpr"];
+  repeated Node subplans = 2 [json_name="subplans"];
+}
+
+message FieldSelect
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  int32 fieldnum = 3 [json_name="fieldnum"];
+  uint32 resulttype = 4 [json_name="resulttype"];
+  int32 resulttypmod = 5 [json_name="resulttypmod"];
+  uint32 resultcollid = 6 [json_name="resultcollid"];
+}
+
+message FieldStore
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  repeated Node newvals = 3 [json_name="newvals"];
+  repeated Node fieldnums = 4 [json_name="fieldnums"];
+  uint32 resulttype = 5 [json_name="resulttype"];
+}
+
+message RelabelType
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  uint32 resulttype = 3 [json_name="resulttype"];
+  int32 resulttypmod = 4 [json_name="resulttypmod"];
+  uint32 resultcollid = 5 [json_name="resultcollid"];
+  CoercionForm relabelformat = 6 [json_name="relabelformat"];
+  int32 location = 7 [json_name="location"];
+}
+
+message CoerceViaIO
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  uint32 resulttype = 3 [json_name="resulttype"];
+  uint32 resultcollid = 4 [json_name="resultcollid"];
+  CoercionForm coerceformat = 5 [json_name="coerceformat"];
+  int32 location = 6 [json_name="location"];
+}
+
+message ArrayCoerceExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  Node elemexpr = 3 [json_name="elemexpr"];
+  uint32 resulttype = 4 [json_name="resulttype"];
+  int32 resulttypmod = 5 [json_name="resulttypmod"];
+  uint32 resultcollid = 6 [json_name="resultcollid"];
+  CoercionForm coerceformat = 7 [json_name="coerceformat"];
+  int32 location = 8 [json_name="location"];
+}
+
+message ConvertRowtypeExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  uint32 resulttype = 3 [json_name="resulttype"];
+  CoercionForm convertformat = 4 [json_name="convertformat"];
+  int32 location = 5 [json_name="location"];
+}
+
+message CollateExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  uint32 coll_oid = 3 [json_name="collOid"];
+  int32 location = 4 [json_name="location"];
+}
+
+message CaseExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 casetype = 2 [json_name="casetype"];
+  uint32 casecollid = 3 [json_name="casecollid"];
+  Node arg = 4 [json_name="arg"];
+  repeated Node args = 5 [json_name="args"];
+  Node defresult = 6 [json_name="defresult"];
+  int32 location = 7 [json_name="location"];
+}
+
+message CaseWhen
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node expr = 2 [json_name="expr"];
+  Node result = 3 [json_name="result"];
+  int32 location = 4 [json_name="location"];
+}
+
+message CaseTestExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 type_id = 2 [json_name="typeId"];
+  int32 type_mod = 3 [json_name="typeMod"];
+  uint32 collation = 4 [json_name="collation"];
+}
+
+message ArrayExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 array_typeid = 2 [json_name="array_typeid"];
+  uint32 array_collid = 3 [json_name="array_collid"];
+  uint32 element_typeid = 4 [json_name="element_typeid"];
+  repeated Node elements = 5 [json_name="elements"];
+  bool multidims = 6 [json_name="multidims"];
+  int32 location = 7 [json_name="location"];
+}
+
+message RowExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  repeated Node args = 2 [json_name="args"];
+  uint32 row_typeid = 3 [json_name="row_typeid"];
+  CoercionForm row_format = 4 [json_name="row_format"];
+  repeated Node colnames = 5 [json_name="colnames"];
+  int32 location = 6 [json_name="location"];
+}
+
+message RowCompareExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  RowCompareType rctype = 2 [json_name="rctype"];
+  repeated Node opnos = 3 [json_name="opnos"];
+  repeated Node opfamilies = 4 [json_name="opfamilies"];
+  repeated Node inputcollids = 5 [json_name="inputcollids"];
+  repeated Node largs = 6 [json_name="largs"];
+  repeated Node rargs = 7 [json_name="rargs"];
+}
+
+message CoalesceExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 coalescetype = 2 [json_name="coalescetype"];
+  uint32 coalescecollid = 3 [json_name="coalescecollid"];
+  repeated Node args = 4 [json_name="args"];
+  int32 location = 5 [json_name="location"];
+}
+
+message MinMaxExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 minmaxtype = 2 [json_name="minmaxtype"];
+  uint32 minmaxcollid = 3 [json_name="minmaxcollid"];
+  uint32 inputcollid = 4 [json_name="inputcollid"];
+  MinMaxOp op = 5 [json_name="op"];
+  repeated Node args = 6 [json_name="args"];
+  int32 location = 7 [json_name="location"];
+}
+
+message SQLValueFunction
+{
+  Node xpr = 1 [json_name="xpr"];
+  SQLValueFunctionOp op = 2 [json_name="op"];
+  uint32 type = 3 [json_name="type"];
+  int32 typmod = 4 [json_name="typmod"];
+  int32 location = 5 [json_name="location"];
+}
+
+message XmlExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  XmlExprOp op = 2 [json_name="op"];
+  string name = 3 [json_name="name"];
+  repeated Node named_args = 4 [json_name="named_args"];
+  repeated Node arg_names = 5 [json_name="arg_names"];
+  repeated Node args = 6 [json_name="args"];
+  XmlOptionType xmloption = 7 [json_name="xmloption"];
+  bool indent = 8 [json_name="indent"];
+  uint32 type = 9 [json_name="type"];
+  int32 typmod = 10 [json_name="typmod"];
+  int32 location = 11 [json_name="location"];
+}
+
+message JsonFormat
+{
+  JsonFormatType format_type = 1 [json_name="format_type"];
+  JsonEncoding encoding = 2 [json_name="encoding"];
+  int32 location = 3 [json_name="location"];
+}
+
+message JsonReturning
+{
+  JsonFormat format = 1 [json_name="format"];
+  uint32 typid = 2 [json_name="typid"];
+  int32 typmod = 3 [json_name="typmod"];
+}
+
+message JsonValueExpr
+{
+  Node raw_expr = 1 [json_name="raw_expr"];
+  Node formatted_expr = 2 [json_name="formatted_expr"];
+  JsonFormat format = 3 [json_name="format"];
+}
+
+message JsonConstructorExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  JsonConstructorType type = 2 [json_name="type"];
+  repeated Node args = 3 [json_name="args"];
+  Node func = 4 [json_name="func"];
+  Node coercion = 5 [json_name="coercion"];
+  JsonReturning returning = 6 [json_name="returning"];
+  bool absent_on_null = 7 [json_name="absent_on_null"];
+  bool unique = 8 [json_name="unique"];
+  int32 location = 9 [json_name="location"];
+}
+
+message JsonIsPredicate
+{
+  Node expr = 1 [json_name="expr"];
+  JsonFormat format = 2 [json_name="format"];
+  JsonValueType item_type = 3 [json_name="item_type"];
+  bool unique_keys = 4 [json_name="unique_keys"];
+  int32 location = 5 [json_name="location"];
+}
+
+message JsonBehavior
+{
+  JsonBehaviorType btype = 1 [json_name="btype"];
+  Node expr = 2 [json_name="expr"];
+  bool coerce = 3 [json_name="coerce"];
+  int32 location = 4 [json_name="location"];
+}
+
+message JsonExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  JsonExprOp op = 2 [json_name="op"];
+  string column_name = 3 [json_name="column_name"];
+  Node formatted_expr = 4 [json_name="formatted_expr"];
+  JsonFormat format = 5 [json_name="format"];
+  Node path_spec = 6 [json_name="path_spec"];
+  JsonReturning returning = 7 [json_name="returning"];
+  repeated Node passing_names = 8 [json_name="passing_names"];
+  repeated Node passing_values = 9 [json_name="passing_values"];
+  JsonBehavior on_empty = 10 [json_name="on_empty"];
+  JsonBehavior on_error = 11 [json_name="on_error"];
+  bool use_io_coercion = 12 [json_name="use_io_coercion"];
+  bool use_json_coercion = 13 [json_name="use_json_coercion"];
+  JsonWrapper wrapper = 14 [json_name="wrapper"];
+  bool omit_quotes = 15 [json_name="omit_quotes"];
+  uint32 collation = 16 [json_name="collation"];
+  int32 location = 17 [json_name="location"];
+}
+
+message JsonTablePath
+{
+  string name = 1 [json_name="name"];
+}
+
+message JsonTablePathScan
+{
+  Node plan = 1 [json_name="plan"];
+  JsonTablePath path = 2 [json_name="path"];
+  bool error_on_error = 3 [json_name="errorOnError"];
+  Node child = 4 [json_name="child"];
+  int32 col_min = 5 [json_name="colMin"];
+  int32 col_max = 6 [json_name="colMax"];
+}
+
+message JsonTableSiblingJoin
+{
+  Node plan = 1 [json_name="plan"];
+  Node lplan = 2 [json_name="lplan"];
+  Node rplan = 3 [json_name="rplan"];
+}
+
+message NullTest
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  NullTestType nulltesttype = 3 [json_name="nulltesttype"];
+  bool argisrow = 4 [json_name="argisrow"];
+  int32 location = 5 [json_name="location"];
+}
+
+message BooleanTest
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  BoolTestType booltesttype = 3 [json_name="booltesttype"];
+  int32 location = 4 [json_name="location"];
+}
+
+message MergeAction
+{
+  MergeMatchKind match_kind = 1 [json_name="matchKind"];
+  CmdType command_type = 2 [json_name="commandType"];
+  OverridingKind override = 3 [json_name="override"];
+  Node qual = 4 [json_name="qual"];
+  repeated Node target_list = 5 [json_name="targetList"];
+  repeated Node update_colnos = 6 [json_name="updateColnos"];
+}
+
+message CoerceToDomain
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node arg = 2 [json_name="arg"];
+  uint32 resulttype = 3 [json_name="resulttype"];
+  int32 resulttypmod = 4 [json_name="resulttypmod"];
+  uint32 resultcollid = 5 [json_name="resultcollid"];
+  CoercionForm coercionformat = 6 [json_name="coercionformat"];
+  int32 location = 7 [json_name="location"];
+}
+
+message CoerceToDomainValue
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 type_id = 2 [json_name="typeId"];
+  int32 type_mod = 3 [json_name="typeMod"];
+  uint32 collation = 4 [json_name="collation"];
+  int32 location = 5 [json_name="location"];
+}
+
+message SetToDefault
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 type_id = 2 [json_name="typeId"];
+  int32 type_mod = 3 [json_name="typeMod"];
+  uint32 collation = 4 [json_name="collation"];
+  int32 location = 5 [json_name="location"];
+}
+
+message CurrentOfExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 cvarno = 2 [json_name="cvarno"];
+  string cursor_name = 3 [json_name="cursor_name"];
+  int32 cursor_param = 4 [json_name="cursor_param"];
+}
+
+message NextValueExpr
+{
+  Node xpr = 1 [json_name="xpr"];
+  uint32 seqid = 2 [json_name="seqid"];
+  uint32 type_id = 3 [json_name="typeId"];
+}
+
+message InferenceElem
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node expr = 2 [json_name="expr"];
+  uint32 infercollid = 3 [json_name="infercollid"];
+  uint32 inferopclass = 4 [json_name="inferopclass"];
+}
+
+message TargetEntry
+{
+  Node xpr = 1 [json_name="xpr"];
+  Node expr = 2 [json_name="expr"];
+  int32 resno = 3 [json_name="resno"];
+  string resname = 4 [json_name="resname"];
+  uint32 ressortgroupref = 5 [json_name="ressortgroupref"];
+  uint32 resorigtbl = 6 [json_name="resorigtbl"];
+  int32 resorigcol = 7 [json_name="resorigcol"];
+  bool resjunk = 8 [json_name="resjunk"];
+}
+
+message RangeTblRef
+{
+  int32 rtindex = 1 [json_name="rtindex"];
+}
+
+message JoinExpr
+{
+  JoinType jointype = 1 [json_name="jointype"];
+  bool is_natural = 2 [json_name="isNatural"];
+  Node larg = 3 [json_name="larg"];
+  Node rarg = 4 [json_name="rarg"];
+  repeated Node using_clause = 5 [json_name="usingClause"];
+  Alias join_using_alias = 6 [json_name="join_using_alias"];
+  Node quals = 7 [json_name="quals"];
+  Alias alias = 8 [json_name="alias"];
+  int32 rtindex = 9 [json_name="rtindex"];
+}
+
+message FromExpr
+{
+  repeated Node fromlist = 1 [json_name="fromlist"];
+  Node quals = 2 [json_name="quals"];
+}
+
+message OnConflictExpr
+{
+  OnConflictAction action = 1 [json_name="action"];
+  repeated Node arbiter_elems = 2 [json_name="arbiterElems"];
+  Node arbiter_where = 3 [json_name="arbiterWhere"];
+  uint32 constraint = 4 [json_name="constraint"];
+  repeated Node on_conflict_set = 5 [json_name="onConflictSet"];
+  Node on_conflict_where = 6 [json_name="onConflictWhere"];
+  int32 excl_rel_index = 7 [json_name="exclRelIndex"];
+  repeated Node excl_rel_tlist = 8 [json_name="exclRelTlist"];
+}
+
+message Query
+{
+  CmdType command_type = 1 [json_name="commandType"];
+  QuerySource query_source = 2 [json_name="querySource"];
+  bool can_set_tag = 3 [json_name="canSetTag"];
+  Node utility_stmt = 4 [json_name="utilityStmt"];
+  int32 result_relation = 5 [json_name="resultRelation"];
+  bool has_aggs = 6 [json_name="hasAggs"];
+  bool has_window_funcs = 7 [json_name="hasWindowFuncs"];
+  bool has_target_srfs = 8 [json_name="hasTargetSRFs"];
+  bool has_sub_links = 9 [json_name="hasSubLinks"];
+  bool has_distinct_on = 10 [json_name="hasDistinctOn"];
+  bool has_recursive = 11 [json_name="hasRecursive"];
+  bool has_modifying_cte = 12 [json_name="hasModifyingCTE"];
+  bool has_for_update = 13 [json_name="hasForUpdate"];
+  bool has_row_security = 14 [json_name="hasRowSecurity"];
+  bool is_return = 15 [json_name="isReturn"];
+  repeated Node cte_list = 16 [json_name="cteList"];
+  repeated Node rtable = 17 [json_name="rtable"];
+  repeated Node rteperminfos = 18 [json_name="rteperminfos"];
+  FromExpr jointree = 19 [json_name="jointree"];
+  repeated Node merge_action_list = 20 [json_name="mergeActionList"];
+  int32 merge_target_relation = 21 [json_name="mergeTargetRelation"];
+  Node merge_join_condition = 22 [json_name="mergeJoinCondition"];
+  repeated Node target_list = 23 [json_name="targetList"];
+  OverridingKind override = 24 [json_name="override"];
+  OnConflictExpr on_conflict = 25 [json_name="onConflict"];
+  repeated Node returning_list = 26 [json_name="returningList"];
+  repeated Node group_clause = 27 [json_name="groupClause"];
+  bool group_distinct = 28 [json_name="groupDistinct"];
+  repeated Node grouping_sets = 29 [json_name="groupingSets"];
+  Node having_qual = 30 [json_name="havingQual"];
+  repeated Node window_clause = 31 [json_name="windowClause"];
+  repeated Node distinct_clause = 32 [json_name="distinctClause"];
+  repeated Node sort_clause = 33 [json_name="sortClause"];
+  Node limit_offset = 34 [json_name="limitOffset"];
+  Node limit_count = 35 [json_name="limitCount"];
+  LimitOption limit_option = 36 [json_name="limitOption"];
+  repeated Node row_marks = 37 [json_name="rowMarks"];
+  Node set_operations = 38 [json_name="setOperations"];
+  repeated Node constraint_deps = 39 [json_name="constraintDeps"];
+  repeated Node with_check_options = 40 [json_name="withCheckOptions"];
+  int32 stmt_location = 41 [json_name="stmt_location"];
+  int32 stmt_len = 42 [json_name="stmt_len"];
+}
+
+message TypeName
+{
+  repeated Node names = 1 [json_name="names"];
+  uint32 type_oid = 2 [json_name="typeOid"];
+  bool setof = 3 [json_name="setof"];
+  bool pct_type = 4 [json_name="pct_type"];
+  repeated Node typmods = 5 [json_name="typmods"];
+  int32 typemod = 6 [json_name="typemod"];
+  repeated Node array_bounds = 7 [json_name="arrayBounds"];
+  int32 location = 8 [json_name="location"];
+}
+
+message ColumnRef
+{
+  repeated Node fields = 1 [json_name="fields"];
+  int32 location = 2 [json_name="location"];
+}
+
+message ParamRef
+{
+  int32 number = 1 [json_name="number"];
+  int32 location = 2 [json_name="location"];
+}
+
+message A_Expr
+{
+  A_Expr_Kind kind = 1 [json_name="kind"];
+  repeated Node name = 2 [json_name="name"];
+  Node lexpr = 3 [json_name="lexpr"];
+  Node rexpr = 4 [json_name="rexpr"];
+  int32 location = 5 [json_name="location"];
+}
+
+message TypeCast
+{
+  Node arg = 1 [json_name="arg"];
+  TypeName type_name = 2 [json_name="typeName"];
+  int32 location = 3 [json_name="location"];
+}
+
+message CollateClause
+{
+  Node arg = 1 [json_name="arg"];
+  repeated Node collname = 2 [json_name="collname"];
+  int32 location = 3 [json_name="location"];
+}
+
+message RoleSpec
+{
+  RoleSpecType roletype = 1 [json_name="roletype"];
+  string rolename = 2 [json_name="rolename"];
+  int32 location = 3 [json_name="location"];
+}
+
+message FuncCall
+{
+  repeated Node funcname = 1 [json_name="funcname"];
+  repeated Node args = 2 [json_name="args"];
+  repeated Node agg_order = 3 [json_name="agg_order"];
+  Node agg_filter = 4 [json_name="agg_filter"];
+  WindowDef over = 5 [json_name="over"];
+  bool agg_within_group = 6 [json_name="agg_within_group"];
+  bool agg_star = 7 [json_name="agg_star"];
+  bool agg_distinct = 8 [json_name="agg_distinct"];
+  bool func_variadic = 9 [json_name="func_variadic"];
+  CoercionForm funcformat = 10 [json_name="funcformat"];
+  int32 location = 11 [json_name="location"];
+}
+
+message A_Star
+{
+}
+
+message A_Indices
+{
+  bool is_slice = 1 [json_name="is_slice"];
+  Node lidx = 2 [json_name="lidx"];
+  Node uidx = 3 [json_name="uidx"];
+}
+
+message A_Indirection
+{
+  Node arg = 1 [json_name="arg"];
+  repeated Node indirection = 2 [json_name="indirection"];
+}
+
+message A_ArrayExpr
+{
+  repeated Node elements = 1 [json_name="elements"];
+  int32 location = 2 [json_name="location"];
+}
+
+message ResTarget
+{
+  string name = 1 [json_name="name"];
+  repeated Node indirection = 2 [json_name="indirection"];
+  Node val = 3 [json_name="val"];
+  int32 location = 4 [json_name="location"];
+}
+
+message MultiAssignRef
+{
+  Node source = 1 [json_name="source"];
+  int32 colno = 2 [json_name="colno"];
+  int32 ncolumns = 3 [json_name="ncolumns"];
+}
+
+message SortBy
+{
+  Node node = 1 [json_name="node"];
+  SortByDir sortby_dir = 2 [json_name="sortby_dir"];
+  SortByNulls sortby_nulls = 3 [json_name="sortby_nulls"];
+  repeated Node use_op = 4 [json_name="useOp"];
+  int32 location = 5 [json_name="location"];
+}
+
+message WindowDef
+{
+  string name = 1 [json_name="name"];
+  string refname = 2 [json_name="refname"];
+  repeated Node partition_clause = 3 [json_name="partitionClause"];
+  repeated Node order_clause = 4 [json_name="orderClause"];
+  int32 frame_options = 5 [json_name="frameOptions"];
+  Node start_offset = 6 [json_name="startOffset"];
+  Node end_offset = 7 [json_name="endOffset"];
+  int32 location = 8 [json_name="location"];
+}
+
+message RangeSubselect
+{
+  bool lateral = 1 [json_name="lateral"];
+  Node subquery = 2 [json_name="subquery"];
+  Alias alias = 3 [json_name="alias"];
+}
+
+message RangeFunction
+{
+  bool lateral = 1 [json_name="lateral"];
+  bool ordinality = 2 [json_name="ordinality"];
+  bool is_rowsfrom = 3 [json_name="is_rowsfrom"];
+  repeated Node functions = 4 [json_name="functions"];
+  Alias alias = 5 [json_name="alias"];
+  repeated Node coldeflist = 6 [json_name="coldeflist"];
+}
+
+message RangeTableFunc
+{
+  bool lateral = 1 [json_name="lateral"];
+  Node docexpr = 2 [json_name="docexpr"];
+  Node rowexpr = 3 [json_name="rowexpr"];
+  repeated Node namespaces = 4 [json_name="namespaces"];
+  repeated Node columns = 5 [json_name="columns"];
+  Alias alias = 6 [json_name="alias"];
+  int32 location = 7 [json_name="location"];
+}
+
+message RangeTableFuncCol
+{
+  string colname = 1 [json_name="colname"];
+  TypeName type_name = 2 [json_name="typeName"];
+  bool for_ordinality = 3 [json_name="for_ordinality"];
+  bool is_not_null = 4 [json_name="is_not_null"];
+  Node colexpr = 5 [json_name="colexpr"];
+  Node coldefexpr = 6 [json_name="coldefexpr"];
+  int32 location = 7 [json_name="location"];
+}
+
+message RangeTableSample
+{
+  Node relation = 1 [json_name="relation"];
+  repeated Node method = 2 [json_name="method"];
+  repeated Node args = 3 [json_name="args"];
+  Node repeatable = 4 [json_name="repeatable"];
+  int32 location = 5 [json_name="location"];
+}
+
+message ColumnDef
+{
+  string colname = 1 [json_name="colname"];
+  TypeName type_name = 2 [json_name="typeName"];
+  string compression = 3 [json_name="compression"];
+  int32 inhcount = 4 [json_name="inhcount"];
+  bool is_local = 5 [json_name="is_local"];
+  bool is_not_null = 6 [json_name="is_not_null"];
+  bool is_from_type = 7 [json_name="is_from_type"];
+  string storage = 8 [json_name="storage"];
+  string storage_name = 9 [json_name="storage_name"];
+  Node raw_default = 10 [json_name="raw_default"];
+  Node cooked_default = 11 [json_name="cooked_default"];
+  string identity = 12 [json_name="identity"];
+  RangeVar identity_sequence = 13 [json_name="identitySequence"];
+  string generated = 14 [json_name="generated"];
+  CollateClause coll_clause = 15 [json_name="collClause"];
+  uint32 coll_oid = 16 [json_name="collOid"];
+  repeated Node constraints = 17 [json_name="constraints"];
+  repeated Node fdwoptions = 18 [json_name="fdwoptions"];
+  int32 location = 19 [json_name="location"];
+}
+
+message TableLikeClause
+{
+  RangeVar relation = 1 [json_name="relation"];
+  uint32 options = 2 [json_name="options"];
+  uint32 relation_oid = 3 [json_name="relationOid"];
+}
+
+message IndexElem
+{
+  string name = 1 [json_name="name"];
+  Node expr = 2 [json_name="expr"];
+  string indexcolname = 3 [json_name="indexcolname"];
+  repeated Node collation = 4 [json_name="collation"];
+  repeated Node opclass = 5 [json_name="opclass"];
+  repeated Node opclassopts = 6 [json_name="opclassopts"];
+  SortByDir ordering = 7 [json_name="ordering"];
+  SortByNulls nulls_ordering = 8 [json_name="nulls_ordering"];
+}
+
+message DefElem
+{
+  string defnamespace = 1 [json_name="defnamespace"];
+  string defname = 2 [json_name="defname"];
+  Node arg = 3 [json_name="arg"];
+  DefElemAction defaction = 4 [json_name="defaction"];
+  int32 location = 5 [json_name="location"];
+}
+
+message LockingClause
+{
+  repeated Node locked_rels = 1 [json_name="lockedRels"];
+  LockClauseStrength strength = 2 [json_name="strength"];
+  LockWaitPolicy wait_policy = 3 [json_name="waitPolicy"];
+}
+
+message XmlSerialize
+{
+  XmlOptionType xmloption = 1 [json_name="xmloption"];
+  Node expr = 2 [json_name="expr"];
+  TypeName type_name = 3 [json_name="typeName"];
+  bool indent = 4 [json_name="indent"];
+  int32 location = 5 [json_name="location"];
+}
+
+message PartitionElem
+{
+  string name = 1 [json_name="name"];
+  Node expr = 2 [json_name="expr"];
+  repeated Node collation = 3 [json_name="collation"];
+  repeated Node opclass = 4 [json_name="opclass"];
+  int32 location = 5 [json_name="location"];
+}
+
+message PartitionSpec
+{
+  PartitionStrategy strategy = 1 [json_name="strategy"];
+  repeated Node part_params = 2 [json_name="partParams"];
+  int32 location = 3 [json_name="location"];
+}
+
+message PartitionBoundSpec
+{
+  string strategy = 1 [json_name="strategy"];
+  bool is_default = 2 [json_name="is_default"];
+  int32 modulus = 3 [json_name="modulus"];
+  int32 remainder = 4 [json_name="remainder"];
+  repeated Node listdatums = 5 [json_name="listdatums"];
+  repeated Node lowerdatums = 6 [json_name="lowerdatums"];
+  repeated Node upperdatums = 7 [json_name="upperdatums"];
+  int32 location = 8 [json_name="location"];
+}
+
+message PartitionRangeDatum
+{
+  PartitionRangeDatumKind kind = 1 [json_name="kind"];
+  Node value = 2 [json_name="value"];
+  int32 location = 3 [json_name="location"];
+}
+
+message SinglePartitionSpec
+{
+}
+
+message PartitionCmd
+{
+  RangeVar name = 1 [json_name="name"];
+  PartitionBoundSpec bound = 2 [json_name="bound"];
+  bool concurrent = 3 [json_name="concurrent"];
+}
+
+message RangeTblEntry
+{
+  Alias alias = 1 [json_name="alias"];
+  Alias eref = 2 [json_name="eref"];
+  RTEKind rtekind = 3 [json_name="rtekind"];
+  uint32 relid = 4 [json_name="relid"];
+  bool inh = 5 [json_name="inh"];
+  string relkind = 6 [json_name="relkind"];
+  int32 rellockmode = 7 [json_name="rellockmode"];
+  uint32 perminfoindex = 8 [json_name="perminfoindex"];
+  TableSampleClause tablesample = 9 [json_name="tablesample"];
+  Query subquery = 10 [json_name="subquery"];
+  bool security_barrier = 11 [json_name="security_barrier"];
+  JoinType jointype = 12 [json_name="jointype"];
+  int32 joinmergedcols = 13 [json_name="joinmergedcols"];
+  repeated Node joinaliasvars = 14 [json_name="joinaliasvars"];
+  repeated Node joinleftcols = 15 [json_name="joinleftcols"];
+  repeated Node joinrightcols = 16 [json_name="joinrightcols"];
+  Alias join_using_alias = 17 [json_name="join_using_alias"];
+  repeated Node functions = 18 [json_name="functions"];
+  bool funcordinality = 19 [json_name="funcordinality"];
+  TableFunc tablefunc = 20 [json_name="tablefunc"];
+  repeated Node values_lists = 21 [json_name="values_lists"];
+  string ctename = 22 [json_name="ctename"];
+  uint32 ctelevelsup = 23 [json_name="ctelevelsup"];
+  bool self_reference = 24 [json_name="self_reference"];
+  repeated Node coltypes = 25 [json_name="coltypes"];
+  repeated Node coltypmods = 26 [json_name="coltypmods"];
+  repeated Node colcollations = 27 [json_name="colcollations"];
+  string enrname = 28 [json_name="enrname"];
+  double enrtuples = 29 [json_name="enrtuples"];
+  bool lateral = 30 [json_name="lateral"];
+  bool in_from_cl = 31 [json_name="inFromCl"];
+  repeated Node security_quals = 32 [json_name="securityQuals"];
+}
+
+message RTEPermissionInfo
+{
+  uint32 relid = 1 [json_name="relid"];
+  bool inh = 2 [json_name="inh"];
+  uint64 required_perms = 3 [json_name="requiredPerms"];
+  uint32 check_as_user = 4 [json_name="checkAsUser"];
+  repeated uint64 selected_cols = 5 [json_name="selectedCols"];
+  repeated uint64 inserted_cols = 6 [json_name="insertedCols"];
+  repeated uint64 updated_cols = 7 [json_name="updatedCols"];
+}
+
+message RangeTblFunction
+{
+  Node funcexpr = 1 [json_name="funcexpr"];
+  int32 funccolcount = 2 [json_name="funccolcount"];
+  repeated Node funccolnames = 3 [json_name="funccolnames"];
+  repeated Node funccoltypes = 4 [json_name="funccoltypes"];
+  repeated Node funccoltypmods = 5 [json_name="funccoltypmods"];
+  repeated Node funccolcollations = 6 [json_name="funccolcollations"];
+  repeated uint64 funcparams = 7 [json_name="funcparams"];
+}
+
+message TableSampleClause
+{
+  uint32 tsmhandler = 1 [json_name="tsmhandler"];
+  repeated Node args = 2 [json_name="args"];
+  Node repeatable = 3 [json_name="repeatable"];
+}
+
+message WithCheckOption
+{
+  WCOKind kind = 1 [json_name="kind"];
+  string relname = 2 [json_name="relname"];
+  string polname = 3 [json_name="polname"];
+  Node qual = 4 [json_name="qual"];
+  bool cascaded = 5 [json_name="cascaded"];
+}
+
+message SortGroupClause
+{
+  uint32 tle_sort_group_ref = 1 [json_name="tleSortGroupRef"];
+  uint32 eqop = 2 [json_name="eqop"];
+  uint32 sortop = 3 [json_name="sortop"];
+  bool nulls_first = 4 [json_name="nulls_first"];
+  bool hashable = 5 [json_name="hashable"];
+}
+
+message GroupingSet
+{
+  GroupingSetKind kind = 1 [json_name="kind"];
+  repeated Node content = 2 [json_name="content"];
+  int32 location = 3 [json_name="location"];
+}
+
+message WindowClause
+{
+  string name = 1 [json_name="name"];
+  string refname = 2 [json_name="refname"];
+  repeated Node partition_clause = 3 [json_name="partitionClause"];
+  repeated Node order_clause = 4 [json_name="orderClause"];
+  int32 frame_options = 5 [json_name="frameOptions"];
+  Node start_offset = 6 [json_name="startOffset"];
+  Node end_offset = 7 [json_name="endOffset"];
+  uint32 start_in_range_func = 8 [json_name="startInRangeFunc"];
+  uint32 end_in_range_func = 9 [json_name="endInRangeFunc"];
+  uint32 in_range_coll = 10 [json_name="inRangeColl"];
+  bool in_range_asc = 11 [json_name="inRangeAsc"];
+  bool in_range_nulls_first = 12 [json_name="inRangeNullsFirst"];
+  uint32 winref = 13 [json_name="winref"];
+  bool copied_order = 14 [json_name="copiedOrder"];
+}
+
+message RowMarkClause
+{
+  uint32 rti = 1 [json_name="rti"];
+  LockClauseStrength strength = 2 [json_name="strength"];
+  LockWaitPolicy wait_policy = 3 [json_name="waitPolicy"];
+  bool pushed_down = 4 [json_name="pushedDown"];
+}
+
+message WithClause
+{
+  repeated Node ctes = 1 [json_name="ctes"];
+  bool recursive = 2 [json_name="recursive"];
+  int32 location = 3 [json_name="location"];
+}
+
+message InferClause
+{
+  repeated Node index_elems = 1 [json_name="indexElems"];
+  Node where_clause = 2 [json_name="whereClause"];
+  string conname = 3 [json_name="conname"];
+  int32 location = 4 [json_name="location"];
+}
+
+message OnConflictClause
+{
+  OnConflictAction action = 1 [json_name="action"];
+  InferClause infer = 2 [json_name="infer"];
+  repeated Node target_list = 3 [json_name="targetList"];
+  Node where_clause = 4 [json_name="whereClause"];
+  int32 location = 5 [json_name="location"];
+}
+
+message CTESearchClause
+{
+  repeated Node search_col_list = 1 [json_name="search_col_list"];
+  bool search_breadth_first = 2 [json_name="search_breadth_first"];
+  string search_seq_column = 3 [json_name="search_seq_column"];
+  int32 location = 4 [json_name="location"];
+}
+
+message CTECycleClause
+{
+  repeated Node cycle_col_list = 1 [json_name="cycle_col_list"];
+  string cycle_mark_column = 2 [json_name="cycle_mark_column"];
+  Node cycle_mark_value = 3 [json_name="cycle_mark_value"];
+  Node cycle_mark_default = 4 [json_name="cycle_mark_default"];
+  string cycle_path_column = 5 [json_name="cycle_path_column"];
+  int32 location = 6 [json_name="location"];
+  uint32 cycle_mark_type = 7 [json_name="cycle_mark_type"];
+  int32 cycle_mark_typmod = 8 [json_name="cycle_mark_typmod"];
+  uint32 cycle_mark_collation = 9 [json_name="cycle_mark_collation"];
+  uint32 cycle_mark_neop = 10 [json_name="cycle_mark_neop"];
+}
+
+message CommonTableExpr
+{
+  string ctename = 1 [json_name="ctename"];
+  repeated Node aliascolnames = 2 [json_name="aliascolnames"];
+  CTEMaterialize ctematerialized = 3 [json_name="ctematerialized"];
+  Node ctequery = 4 [json_name="ctequery"];
+  CTESearchClause search_clause = 5 [json_name="search_clause"];
+  CTECycleClause cycle_clause = 6 [json_name="cycle_clause"];
+  int32 location = 7 [json_name="location"];
+  bool cterecursive = 8 [json_name="cterecursive"];
+  int32 cterefcount = 9 [json_name="cterefcount"];
+  repeated Node ctecolnames = 10 [json_name="ctecolnames"];
+  repeated Node ctecoltypes = 11 [json_name="ctecoltypes"];
+  repeated Node ctecoltypmods = 12 [json_name="ctecoltypmods"];
+  repeated Node ctecolcollations = 13 [json_name="ctecolcollations"];
+}
+
+message MergeWhenClause
+{
+  MergeMatchKind match_kind = 1 [json_name="matchKind"];
+  CmdType command_type = 2 [json_name="commandType"];
+  OverridingKind override = 3 [json_name="override"];
+  Node condition = 4 [json_name="condition"];
+  repeated Node target_list = 5 [json_name="targetList"];
+  repeated Node values = 6 [json_name="values"];
+}
+
+message TriggerTransition
+{
+  string name = 1 [json_name="name"];
+  bool is_new = 2 [json_name="isNew"];
+  bool is_table = 3 [json_name="isTable"];
+}
+
+message JsonOutput
+{
+  TypeName type_name = 1 [json_name="typeName"];
+  JsonReturning returning = 2 [json_name="returning"];
+}
+
+message JsonArgument
+{
+  JsonValueExpr val = 1 [json_name="val"];
+  string name = 2 [json_name="name"];
+}
+
+message JsonFuncExpr
+{
+  JsonExprOp op = 1 [json_name="op"];
+  string column_name = 2 [json_name="column_name"];
+  JsonValueExpr context_item = 3 [json_name="context_item"];
+  Node pathspec = 4 [json_name="pathspec"];
+  repeated Node passing = 5 [json_name="passing"];
+  JsonOutput output = 6 [json_name="output"];
+  JsonBehavior on_empty = 7 [json_name="on_empty"];
+  JsonBehavior on_error = 8 [json_name="on_error"];
+  JsonWrapper wrapper = 9 [json_name="wrapper"];
+  JsonQuotes quotes = 10 [json_name="quotes"];
+  int32 location = 11 [json_name="location"];
+}
+
+message JsonTablePathSpec
+{
+  Node string = 1 [json_name="string"];
+  string name = 2 [json_name="name"];
+  int32 name_location = 3 [json_name="name_location"];
+  int32 location = 4 [json_name="location"];
+}
+
+message JsonTable
+{
+  JsonValueExpr context_item = 1 [json_name="context_item"];
+  JsonTablePathSpec pathspec = 2 [json_name="pathspec"];
+  repeated Node passing = 3 [json_name="passing"];
+  repeated Node columns = 4 [json_name="columns"];
+  JsonBehavior on_error = 5 [json_name="on_error"];
+  Alias alias = 6 [json_name="alias"];
+  bool lateral = 7 [json_name="lateral"];
+  int32 location = 8 [json_name="location"];
+}
+
+message JsonTableColumn
+{
+  JsonTableColumnType coltype = 1 [json_name="coltype"];
+  string name = 2 [json_name="name"];
+  TypeName type_name = 3 [json_name="typeName"];
+  JsonTablePathSpec pathspec = 4 [json_name="pathspec"];
+  JsonFormat format = 5 [json_name="format"];
+  JsonWrapper wrapper = 6 [json_name="wrapper"];
+  JsonQuotes quotes = 7 [json_name="quotes"];
+  repeated Node columns = 8 [json_name="columns"];
+  JsonBehavior on_empty = 9 [json_name="on_empty"];
+  JsonBehavior on_error = 10 [json_name="on_error"];
+  int32 location = 11 [json_name="location"];
+}
+
+message JsonKeyValue
+{
+  Node key = 1 [json_name="key"];
+  JsonValueExpr value = 2 [json_name="value"];
+}
+
+message JsonParseExpr
+{
+  JsonValueExpr expr = 1 [json_name="expr"];
+  JsonOutput output = 2 [json_name="output"];
+  bool unique_keys = 3 [json_name="unique_keys"];
+  int32 location = 4 [json_name="location"];
+}
+
+message JsonScalarExpr
+{
+  Node expr = 1 [json_name="expr"];
+  JsonOutput output = 2 [json_name="output"];
+  int32 location = 3 [json_name="location"];
+}
+
+message JsonSerializeExpr
+{
+  JsonValueExpr expr = 1 [json_name="expr"];
+  JsonOutput output = 2 [json_name="output"];
+  int32 location = 3 [json_name="location"];
+}
+
+message JsonObjectConstructor
+{
+  repeated Node exprs = 1 [json_name="exprs"];
+  JsonOutput output = 2 [json_name="output"];
+  bool absent_on_null = 3 [json_name="absent_on_null"];
+  bool unique = 4 [json_name="unique"];
+  int32 location = 5 [json_name="location"];
+}
+
+message JsonArrayConstructor
+{
+  repeated Node exprs = 1 [json_name="exprs"];
+  JsonOutput output = 2 [json_name="output"];
+  bool absent_on_null = 3 [json_name="absent_on_null"];
+  int32 location = 4 [json_name="location"];
+}
+
+message JsonArrayQueryConstructor
+{
+  Node query = 1 [json_name="query"];
+  JsonOutput output = 2 [json_name="output"];
+  JsonFormat format = 3 [json_name="format"];
+  bool absent_on_null = 4 [json_name="absent_on_null"];
+  int32 location = 5 [json_name="location"];
+}
+
+message JsonAggConstructor
+{
+  JsonOutput output = 1 [json_name="output"];
+  Node agg_filter = 2 [json_name="agg_filter"];
+  repeated Node agg_order = 3 [json_name="agg_order"];
+  WindowDef over = 4 [json_name="over"];
+  int32 location = 5 [json_name="location"];
+}
+
+message JsonObjectAgg
+{
+  JsonAggConstructor constructor = 1 [json_name="constructor"];
+  JsonKeyValue arg = 2 [json_name="arg"];
+  bool absent_on_null = 3 [json_name="absent_on_null"];
+  bool unique = 4 [json_name="unique"];
+}
+
+message JsonArrayAgg
+{
+  JsonAggConstructor constructor = 1 [json_name="constructor"];
+  JsonValueExpr arg = 2 [json_name="arg"];
+  bool absent_on_null = 3 [json_name="absent_on_null"];
+}
+
+message RawStmt
+{
+  Node stmt = 1 [json_name="stmt"];
+  int32 stmt_location = 2 [json_name="stmt_location"];
+  int32 stmt_len = 3 [json_name="stmt_len"];
+}
+
+message InsertStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  repeated Node cols = 2 [json_name="cols"];
+  Node select_stmt = 3 [json_name="selectStmt"];
+  OnConflictClause on_conflict_clause = 4 [json_name="onConflictClause"];
+  repeated Node returning_list = 5 [json_name="returningList"];
+  WithClause with_clause = 6 [json_name="withClause"];
+  OverridingKind override = 7 [json_name="override"];
+}
+
+message DeleteStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  repeated Node using_clause = 2 [json_name="usingClause"];
+  Node where_clause = 3 [json_name="whereClause"];
+  repeated Node returning_list = 4 [json_name="returningList"];
+  WithClause with_clause = 5 [json_name="withClause"];
+}
+
+message UpdateStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  repeated Node target_list = 2 [json_name="targetList"];
+  Node where_clause = 3 [json_name="whereClause"];
+  repeated Node from_clause = 4 [json_name="fromClause"];
+  repeated Node returning_list = 5 [json_name="returningList"];
+  WithClause with_clause = 6 [json_name="withClause"];
+}
+
+message MergeStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  Node source_relation = 2 [json_name="sourceRelation"];
+  Node join_condition = 3 [json_name="joinCondition"];
+  repeated Node merge_when_clauses = 4 [json_name="mergeWhenClauses"];
+  repeated Node returning_list = 5 [json_name="returningList"];
+  WithClause with_clause = 6 [json_name="withClause"];
+}
+
+message SelectStmt
+{
+  repeated Node distinct_clause = 1 [json_name="distinctClause"];
+  IntoClause into_clause = 2 [json_name="intoClause"];
+  repeated Node target_list = 3 [json_name="targetList"];
+  repeated Node from_clause = 4 [json_name="fromClause"];
+  Node where_clause = 5 [json_name="whereClause"];
+  repeated Node group_clause = 6 [json_name="groupClause"];
+  bool group_distinct = 7 [json_name="groupDistinct"];
+  Node having_clause = 8 [json_name="havingClause"];
+  repeated Node window_clause = 9 [json_name="windowClause"];
+  repeated Node values_lists = 10 [json_name="valuesLists"];
+  repeated Node sort_clause = 11 [json_name="sortClause"];
+  Node limit_offset = 12 [json_name="limitOffset"];
+  Node limit_count = 13 [json_name="limitCount"];
+  LimitOption limit_option = 14 [json_name="limitOption"];
+  repeated Node locking_clause = 15 [json_name="lockingClause"];
+  WithClause with_clause = 16 [json_name="withClause"];
+  SetOperation op = 17 [json_name="op"];
+  bool all = 18 [json_name="all"];
+  SelectStmt larg = 19 [json_name="larg"];
+  SelectStmt rarg = 20 [json_name="rarg"];
+}
+
+message SetOperationStmt
+{
+  SetOperation op = 1 [json_name="op"];
+  bool all = 2 [json_name="all"];
+  Node larg = 3 [json_name="larg"];
+  Node rarg = 4 [json_name="rarg"];
+  repeated Node col_types = 5 [json_name="colTypes"];
+  repeated Node col_typmods = 6 [json_name="colTypmods"];
+  repeated Node col_collations = 7 [json_name="colCollations"];
+  repeated Node group_clauses = 8 [json_name="groupClauses"];
+}
+
+message ReturnStmt
+{
+  Node returnval = 1 [json_name="returnval"];
+}
+
+message PLAssignStmt
+{
+  string name = 1 [json_name="name"];
+  repeated Node indirection = 2 [json_name="indirection"];
+  int32 nnames = 3 [json_name="nnames"];
+  SelectStmt val = 4 [json_name="val"];
+  int32 location = 5 [json_name="location"];
+}
+
+message CreateSchemaStmt
+{
+  string schemaname = 1 [json_name="schemaname"];
+  RoleSpec authrole = 2 [json_name="authrole"];
+  repeated Node schema_elts = 3 [json_name="schemaElts"];
+  bool if_not_exists = 4 [json_name="if_not_exists"];
+}
+
+message AlterTableStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  repeated Node cmds = 2 [json_name="cmds"];
+  ObjectType objtype = 3 [json_name="objtype"];
+  bool missing_ok = 4 [json_name="missing_ok"];
+}
+
+message ReplicaIdentityStmt
+{
+  string identity_type = 1 [json_name="identity_type"];
+  string name = 2 [json_name="name"];
+}
+
+message AlterTableCmd
+{
+  AlterTableType subtype = 1 [json_name="subtype"];
+  string name = 2 [json_name="name"];
+  int32 num = 3 [json_name="num"];
+  RoleSpec newowner = 4 [json_name="newowner"];
+  Node def = 5 [json_name="def"];
+  DropBehavior behavior = 6 [json_name="behavior"];
+  bool missing_ok = 7 [json_name="missing_ok"];
+  bool recurse = 8 [json_name="recurse"];
+}
+
+message AlterCollationStmt
+{
+  repeated Node collname = 1 [json_name="collname"];
+}
+
+message AlterDomainStmt
+{
+  string subtype = 1 [json_name="subtype"];
+  repeated Node type_name = 2 [json_name="typeName"];
+  string name = 3 [json_name="name"];
+  Node def = 4 [json_name="def"];
+  DropBehavior behavior = 5 [json_name="behavior"];
+  bool missing_ok = 6 [json_name="missing_ok"];
+}
+
+message GrantStmt
+{
+  bool is_grant = 1 [json_name="is_grant"];
+  GrantTargetType targtype = 2 [json_name="targtype"];
+  ObjectType objtype = 3 [json_name="objtype"];
+  repeated Node objects = 4 [json_name="objects"];
+  repeated Node privileges = 5 [json_name="privileges"];
+  repeated Node grantees = 6 [json_name="grantees"];
+  bool grant_option = 7 [json_name="grant_option"];
+  RoleSpec grantor = 8 [json_name="grantor"];
+  DropBehavior behavior = 9 [json_name="behavior"];
+}
+
+message ObjectWithArgs
+{
+  repeated Node objname = 1 [json_name="objname"];
+  repeated Node objargs = 2 [json_name="objargs"];
+  repeated Node objfuncargs = 3 [json_name="objfuncargs"];
+  bool args_unspecified = 4 [json_name="args_unspecified"];
+}
+
+message AccessPriv
+{
+  string priv_name = 1 [json_name="priv_name"];
+  repeated Node cols = 2 [json_name="cols"];
+}
+
+message GrantRoleStmt
+{
+  repeated Node granted_roles = 1 [json_name="granted_roles"];
+  repeated Node grantee_roles = 2 [json_name="grantee_roles"];
+  bool is_grant = 3 [json_name="is_grant"];
+  repeated Node opt = 4 [json_name="opt"];
+  RoleSpec grantor = 5 [json_name="grantor"];
+  DropBehavior behavior = 6 [json_name="behavior"];
+}
+
+message AlterDefaultPrivilegesStmt
+{
+  repeated Node options = 1 [json_name="options"];
+  GrantStmt action = 2 [json_name="action"];
+}
+
+message CopyStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  Node query = 2 [json_name="query"];
+  repeated Node attlist = 3 [json_name="attlist"];
+  bool is_from = 4 [json_name="is_from"];
+  bool is_program = 5 [json_name="is_program"];
+  string filename = 6 [json_name="filename"];
+  repeated Node options = 7 [json_name="options"];
+  Node where_clause = 8 [json_name="whereClause"];
+}
+
+message VariableSetStmt
+{
+  VariableSetKind kind = 1 [json_name="kind"];
+  string name = 2 [json_name="name"];
+  repeated Node args = 3 [json_name="args"];
+  bool is_local = 4 [json_name="is_local"];
+}
+
+message VariableShowStmt
+{
+  string name = 1 [json_name="name"];
+}
+
+message CreateStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  repeated Node table_elts = 2 [json_name="tableElts"];
+  repeated Node inh_relations = 3 [json_name="inhRelations"];
+  PartitionBoundSpec partbound = 4 [json_name="partbound"];
+  PartitionSpec partspec = 5 [json_name="partspec"];
+  TypeName of_typename = 6 [json_name="ofTypename"];
+  repeated Node constraints = 7 [json_name="constraints"];
+  repeated Node options = 8 [json_name="options"];
+  OnCommitAction oncommit = 9 [json_name="oncommit"];
+  string tablespacename = 10 [json_name="tablespacename"];
+  string access_method = 11 [json_name="accessMethod"];
+  bool if_not_exists = 12 [json_name="if_not_exists"];
+}
+
+message Constraint
+{
+  ConstrType contype = 1 [json_name="contype"];
+  string conname = 2 [json_name="conname"];
+  bool deferrable = 3 [json_name="deferrable"];
+  bool initdeferred = 4 [json_name="initdeferred"];
+  bool skip_validation = 5 [json_name="skip_validation"];
+  bool initially_valid = 6 [json_name="initially_valid"];
+  bool is_no_inherit = 7 [json_name="is_no_inherit"];
+  Node raw_expr = 8 [json_name="raw_expr"];
+  string cooked_expr = 9 [json_name="cooked_expr"];
+  string generated_when = 10 [json_name="generated_when"];
+  int32 inhcount = 11 [json_name="inhcount"];
+  bool nulls_not_distinct = 12 [json_name="nulls_not_distinct"];
+  repeated Node keys = 13 [json_name="keys"];
+  repeated Node including = 14 [json_name="including"];
+  repeated Node exclusions = 15 [json_name="exclusions"];
+  repeated Node options = 16 [json_name="options"];
+  string indexname = 17 [json_name="indexname"];
+  string indexspace = 18 [json_name="indexspace"];
+  bool reset_default_tblspc = 19 [json_name="reset_default_tblspc"];
+  string access_method = 20 [json_name="access_method"];
+  Node where_clause = 21 [json_name="where_clause"];
+  RangeVar pktable = 22 [json_name="pktable"];
+  repeated Node fk_attrs = 23 [json_name="fk_attrs"];
+  repeated Node pk_attrs = 24 [json_name="pk_attrs"];
+  string fk_matchtype = 25 [json_name="fk_matchtype"];
+  string fk_upd_action = 26 [json_name="fk_upd_action"];
+  string fk_del_action = 27 [json_name="fk_del_action"];
+  repeated Node fk_del_set_cols = 28 [json_name="fk_del_set_cols"];
+  repeated Node old_conpfeqop = 29 [json_name="old_conpfeqop"];
+  uint32 old_pktable_oid = 30 [json_name="old_pktable_oid"];
+  int32 location = 31 [json_name="location"];
+}
+
+message CreateTableSpaceStmt
+{
+  string tablespacename = 1 [json_name="tablespacename"];
+  RoleSpec owner = 2 [json_name="owner"];
+  string location = 3 [json_name="location"];
+  repeated Node options = 4 [json_name="options"];
+}
+
+message DropTableSpaceStmt
+{
+  string tablespacename = 1 [json_name="tablespacename"];
+  bool missing_ok = 2 [json_name="missing_ok"];
+}
+
+message AlterTableSpaceOptionsStmt
+{
+  string tablespacename = 1 [json_name="tablespacename"];
+  repeated Node options = 2 [json_name="options"];
+  bool is_reset = 3 [json_name="isReset"];
+}
+
+message AlterTableMoveAllStmt
+{
+  string orig_tablespacename = 1 [json_name="orig_tablespacename"];
+  ObjectType objtype = 2 [json_name="objtype"];
+  repeated Node roles = 3 [json_name="roles"];
+  string new_tablespacename = 4 [json_name="new_tablespacename"];
+  bool nowait = 5 [json_name="nowait"];
+}
+
+message CreateExtensionStmt
+{
+  string extname = 1 [json_name="extname"];
+  bool if_not_exists = 2 [json_name="if_not_exists"];
+  repeated Node options = 3 [json_name="options"];
+}
+
+message AlterExtensionStmt
+{
+  string extname = 1 [json_name="extname"];
+  repeated Node options = 2 [json_name="options"];
+}
+
+message AlterExtensionContentsStmt
+{
+  string extname = 1 [json_name="extname"];
+  int32 action = 2 [json_name="action"];
+  ObjectType objtype = 3 [json_name="objtype"];
+  Node object = 4 [json_name="object"];
+}
+
+message CreateFdwStmt
+{
+  string fdwname = 1 [json_name="fdwname"];
+  repeated Node func_options = 2 [json_name="func_options"];
+  repeated Node options = 3 [json_name="options"];
+}
+
+message AlterFdwStmt
+{
+  string fdwname = 1 [json_name="fdwname"];
+  repeated Node func_options = 2 [json_name="func_options"];
+  repeated Node options = 3 [json_name="options"];
+}
+
+message CreateForeignServerStmt
+{
+  string servername = 1 [json_name="servername"];
+  string servertype = 2 [json_name="servertype"];
+  string version = 3 [json_name="version"];
+  string fdwname = 4 [json_name="fdwname"];
+  bool if_not_exists = 5 [json_name="if_not_exists"];
+  repeated Node options = 6 [json_name="options"];
+}
+
+message AlterForeignServerStmt
+{
+  string servername = 1 [json_name="servername"];
+  string version = 2 [json_name="version"];
+  repeated Node options = 3 [json_name="options"];
+  bool has_version = 4 [json_name="has_version"];
+}
+
+message CreateForeignTableStmt
+{
+  CreateStmt base_stmt = 1 [json_name="base"];
+  string servername = 2 [json_name="servername"];
+  repeated Node options = 3 [json_name="options"];
+}
+
+message CreateUserMappingStmt
+{
+  RoleSpec user = 1 [json_name="user"];
+  string servername = 2 [json_name="servername"];
+  bool if_not_exists = 3 [json_name="if_not_exists"];
+  repeated Node options = 4 [json_name="options"];
+}
+
+message AlterUserMappingStmt
+{
+  RoleSpec user = 1 [json_name="user"];
+  string servername = 2 [json_name="servername"];
+  repeated Node options = 3 [json_name="options"];
+}
+
+message DropUserMappingStmt
+{
+  RoleSpec user = 1 [json_name="user"];
+  string servername = 2 [json_name="servername"];
+  bool missing_ok = 3 [json_name="missing_ok"];
+}
+
+message ImportForeignSchemaStmt
+{
+  string server_name = 1 [json_name="server_name"];
+  string remote_schema = 2 [json_name="remote_schema"];
+  string local_schema = 3 [json_name="local_schema"];
+  ImportForeignSchemaType list_type = 4 [json_name="list_type"];
+  repeated Node table_list = 5 [json_name="table_list"];
+  repeated Node options = 6 [json_name="options"];
+}
+
+message CreatePolicyStmt
+{
+  string policy_name = 1 [json_name="policy_name"];
+  RangeVar table = 2 [json_name="table"];
+  string cmd_name = 3 [json_name="cmd_name"];
+  bool permissive = 4 [json_name="permissive"];
+  repeated Node roles = 5 [json_name="roles"];
+  Node qual = 6 [json_name="qual"];
+  Node with_check = 7 [json_name="with_check"];
+}
+
+message AlterPolicyStmt
+{
+  string policy_name = 1 [json_name="policy_name"];
+  RangeVar table = 2 [json_name="table"];
+  repeated Node roles = 3 [json_name="roles"];
+  Node qual = 4 [json_name="qual"];
+  Node with_check = 5 [json_name="with_check"];
+}
+
+message CreateAmStmt
+{
+  string amname = 1 [json_name="amname"];
+  repeated Node handler_name = 2 [json_name="handler_name"];
+  string amtype = 3 [json_name="amtype"];
+}
+
+message CreateTrigStmt
+{
+  bool replace = 1 [json_name="replace"];
+  bool isconstraint = 2 [json_name="isconstraint"];
+  string trigname = 3 [json_name="trigname"];
+  RangeVar relation = 4 [json_name="relation"];
+  repeated Node funcname = 5 [json_name="funcname"];
+  repeated Node args = 6 [json_name="args"];
+  bool row = 7 [json_name="row"];
+  int32 timing = 8 [json_name="timing"];
+  int32 events = 9 [json_name="events"];
+  repeated Node columns = 10 [json_name="columns"];
+  Node when_clause = 11 [json_name="whenClause"];
+  repeated Node transition_rels = 12 [json_name="transitionRels"];
+  bool deferrable = 13 [json_name="deferrable"];
+  bool initdeferred = 14 [json_name="initdeferred"];
+  RangeVar constrrel = 15 [json_name="constrrel"];
+}
+
+message CreateEventTrigStmt
+{
+  string trigname = 1 [json_name="trigname"];
+  string eventname = 2 [json_name="eventname"];
+  repeated Node whenclause = 3 [json_name="whenclause"];
+  repeated Node funcname = 4 [json_name="funcname"];
+}
+
+message AlterEventTrigStmt
+{
+  string trigname = 1 [json_name="trigname"];
+  string tgenabled = 2 [json_name="tgenabled"];
+}
+
+message CreatePLangStmt
+{
+  bool replace = 1 [json_name="replace"];
+  string plname = 2 [json_name="plname"];
+  repeated Node plhandler = 3 [json_name="plhandler"];
+  repeated Node plinline = 4 [json_name="plinline"];
+  repeated Node plvalidator = 5 [json_name="plvalidator"];
+  bool pltrusted = 6 [json_name="pltrusted"];
+}
+
+message CreateRoleStmt
+{
+  RoleStmtType stmt_type = 1 [json_name="stmt_type"];
+  string role = 2 [json_name="role"];
+  repeated Node options = 3 [json_name="options"];
+}
+
+message AlterRoleStmt
+{
+  RoleSpec role = 1 [json_name="role"];
+  repeated Node options = 2 [json_name="options"];
+  int32 action = 3 [json_name="action"];
+}
+
+message AlterRoleSetStmt
+{
+  RoleSpec role = 1 [json_name="role"];
+  string database = 2 [json_name="database"];
+  VariableSetStmt setstmt = 3 [json_name="setstmt"];
+}
+
+message DropRoleStmt
+{
+  repeated Node roles = 1 [json_name="roles"];
+  bool missing_ok = 2 [json_name="missing_ok"];
+}
+
+message CreateSeqStmt
+{
+  RangeVar sequence = 1 [json_name="sequence"];
+  repeated Node options = 2 [json_name="options"];
+  uint32 owner_id = 3 [json_name="ownerId"];
+  bool for_identity = 4 [json_name="for_identity"];
+  bool if_not_exists = 5 [json_name="if_not_exists"];
+}
+
+message AlterSeqStmt
+{
+  RangeVar sequence = 1 [json_name="sequence"];
+  repeated Node options = 2 [json_name="options"];
+  bool for_identity = 3 [json_name="for_identity"];
+  bool missing_ok = 4 [json_name="missing_ok"];
+}
+
+message DefineStmt
+{
+  ObjectType kind = 1 [json_name="kind"];
+  bool oldstyle = 2 [json_name="oldstyle"];
+  repeated Node defnames = 3 [json_name="defnames"];
+  repeated Node args = 4 [json_name="args"];
+  repeated Node definition = 5 [json_name="definition"];
+  bool if_not_exists = 6 [json_name="if_not_exists"];
+  bool replace = 7 [json_name="replace"];
+}
+
+message CreateDomainStmt
+{
+  repeated Node domainname = 1 [json_name="domainname"];
+  TypeName type_name = 2 [json_name="typeName"];
+  CollateClause coll_clause = 3 [json_name="collClause"];
+  repeated Node constraints = 4 [json_name="constraints"];
+}
+
+message CreateOpClassStmt
+{
+  repeated Node opclassname = 1 [json_name="opclassname"];
+  repeated Node opfamilyname = 2 [json_name="opfamilyname"];
+  string amname = 3 [json_name="amname"];
+  TypeName datatype = 4 [json_name="datatype"];
+  repeated Node items = 5 [json_name="items"];
+  bool is_default = 6 [json_name="isDefault"];
+}
+
+message CreateOpClassItem
+{
+  int32 itemtype = 1 [json_name="itemtype"];
+  ObjectWithArgs name = 2 [json_name="name"];
+  int32 number = 3 [json_name="number"];
+  repeated Node order_family = 4 [json_name="order_family"];
+  repeated Node class_args = 5 [json_name="class_args"];
+  TypeName storedtype = 6 [json_name="storedtype"];
+}
+
+message CreateOpFamilyStmt
+{
+  repeated Node opfamilyname = 1 [json_name="opfamilyname"];
+  string amname = 2 [json_name="amname"];
+}
+
+message AlterOpFamilyStmt
+{
+  repeated Node opfamilyname = 1 [json_name="opfamilyname"];
+  string amname = 2 [json_name="amname"];
+  bool is_drop = 3 [json_name="isDrop"];
+  repeated Node items = 4 [json_name="items"];
+}
+
+message DropStmt
+{
+  repeated Node objects = 1 [json_name="objects"];
+  ObjectType remove_type = 2 [json_name="removeType"];
+  DropBehavior behavior = 3 [json_name="behavior"];
+  bool missing_ok = 4 [json_name="missing_ok"];
+  bool concurrent = 5 [json_name="concurrent"];
+}
+
+message TruncateStmt
+{
+  repeated Node relations = 1 [json_name="relations"];
+  bool restart_seqs = 2 [json_name="restart_seqs"];
+  DropBehavior behavior = 3 [json_name="behavior"];
+}
+
+message CommentStmt
+{
+  ObjectType objtype = 1 [json_name="objtype"];
+  Node object = 2 [json_name="object"];
+  string comment = 3 [json_name="comment"];
+}
+
+message SecLabelStmt
+{
+  ObjectType objtype = 1 [json_name="objtype"];
+  Node object = 2 [json_name="object"];
+  string provider = 3 [json_name="provider"];
+  string label = 4 [json_name="label"];
+}
+
+message DeclareCursorStmt
+{
+  string portalname = 1 [json_name="portalname"];
+  int32 options = 2 [json_name="options"];
+  Node query = 3 [json_name="query"];
+}
+
+message ClosePortalStmt
+{
+  string portalname = 1 [json_name="portalname"];
+}
+
+message FetchStmt
+{
+  FetchDirection direction = 1 [json_name="direction"];
+  int64 how_many = 2 [json_name="howMany"];
+  string portalname = 3 [json_name="portalname"];
+  bool ismove = 4 [json_name="ismove"];
+}
+
+message IndexStmt
+{
+  string idxname = 1 [json_name="idxname"];
+  RangeVar relation = 2 [json_name="relation"];
+  string access_method = 3 [json_name="accessMethod"];
+  string table_space = 4 [json_name="tableSpace"];
+  repeated Node index_params = 5 [json_name="indexParams"];
+  repeated Node index_including_params = 6 [json_name="indexIncludingParams"];
+  repeated Node options = 7 [json_name="options"];
+  Node where_clause = 8 [json_name="whereClause"];
+  repeated Node exclude_op_names = 9 [json_name="excludeOpNames"];
+  string idxcomment = 10 [json_name="idxcomment"];
+  uint32 index_oid = 11 [json_name="indexOid"];
+  uint32 old_number = 12 [json_name="oldNumber"];
+  uint32 old_create_subid = 13 [json_name="oldCreateSubid"];
+  uint32 old_first_relfilelocator_subid = 14 [json_name="oldFirstRelfilelocatorSubid"];
+  bool unique = 15 [json_name="unique"];
+  bool nulls_not_distinct = 16 [json_name="nulls_not_distinct"];
+  bool primary = 17 [json_name="primary"];
+  bool isconstraint = 18 [json_name="isconstraint"];
+  bool deferrable = 19 [json_name="deferrable"];
+  bool initdeferred = 20 [json_name="initdeferred"];
+  bool transformed = 21 [json_name="transformed"];
+  bool concurrent = 22 [json_name="concurrent"];
+  bool if_not_exists = 23 [json_name="if_not_exists"];
+  bool reset_default_tblspc = 24 [json_name="reset_default_tblspc"];
+}
+
+message CreateStatsStmt
+{
+  repeated Node defnames = 1 [json_name="defnames"];
+  repeated Node stat_types = 2 [json_name="stat_types"];
+  repeated Node exprs = 3 [json_name="exprs"];
+  repeated Node relations = 4 [json_name="relations"];
+  string stxcomment = 5 [json_name="stxcomment"];
+  bool transformed = 6 [json_name="transformed"];
+  bool if_not_exists = 7 [json_name="if_not_exists"];
+}
+
+message StatsElem
+{
+  string name = 1 [json_name="name"];
+  Node expr = 2 [json_name="expr"];
+}
+
+message AlterStatsStmt
+{
+  repeated Node defnames = 1 [json_name="defnames"];
+  Node stxstattarget = 2 [json_name="stxstattarget"];
+  bool missing_ok = 3 [json_name="missing_ok"];
+}
+
+message CreateFunctionStmt
+{
+  bool is_procedure = 1 [json_name="is_procedure"];
+  bool replace = 2 [json_name="replace"];
+  repeated Node funcname = 3 [json_name="funcname"];
+  repeated Node parameters = 4 [json_name="parameters"];
+  TypeName return_type = 5 [json_name="returnType"];
+  repeated Node options = 6 [json_name="options"];
+  Node sql_body = 7 [json_name="sql_body"];
+}
+
+message FunctionParameter
+{
+  string name = 1 [json_name="name"];
+  TypeName arg_type = 2 [json_name="argType"];
+  FunctionParameterMode mode = 3 [json_name="mode"];
+  Node defexpr = 4 [json_name="defexpr"];
+}
+
+message AlterFunctionStmt
+{
+  ObjectType objtype = 1 [json_name="objtype"];
+  ObjectWithArgs func = 2 [json_name="func"];
+  repeated Node actions = 3 [json_name="actions"];
+}
+
+message DoStmt
+{
+  repeated Node args = 1 [json_name="args"];
+}
+
+message InlineCodeBlock
+{
+  string source_text = 1 [json_name="source_text"];
+  uint32 lang_oid = 2 [json_name="langOid"];
+  bool lang_is_trusted = 3 [json_name="langIsTrusted"];
+  bool atomic = 4 [json_name="atomic"];
+}
+
+message CallStmt
+{
+  FuncCall funccall = 1 [json_name="funccall"];
+  FuncExpr funcexpr = 2 [json_name="funcexpr"];
+  repeated Node outargs = 3 [json_name="outargs"];
+}
+
+message CallContext
+{
+  bool atomic = 1 [json_name="atomic"];
+}
+
+message RenameStmt
+{
+  ObjectType rename_type = 1 [json_name="renameType"];
+  ObjectType relation_type = 2 [json_name="relationType"];
+  RangeVar relation = 3 [json_name="relation"];
+  Node object = 4 [json_name="object"];
+  string subname = 5 [json_name="subname"];
+  string newname = 6 [json_name="newname"];
+  DropBehavior behavior = 7 [json_name="behavior"];
+  bool missing_ok = 8 [json_name="missing_ok"];
+}
+
+message AlterObjectDependsStmt
+{
+  ObjectType object_type = 1 [json_name="objectType"];
+  RangeVar relation = 2 [json_name="relation"];
+  Node object = 3 [json_name="object"];
+  String extname = 4 [json_name="extname"];
+  bool remove = 5 [json_name="remove"];
+}
+
+message AlterObjectSchemaStmt
+{
+  ObjectType object_type = 1 [json_name="objectType"];
+  RangeVar relation = 2 [json_name="relation"];
+  Node object = 3 [json_name="object"];
+  string newschema = 4 [json_name="newschema"];
+  bool missing_ok = 5 [json_name="missing_ok"];
+}
+
+message AlterOwnerStmt
+{
+  ObjectType object_type = 1 [json_name="objectType"];
+  RangeVar relation = 2 [json_name="relation"];
+  Node object = 3 [json_name="object"];
+  RoleSpec newowner = 4 [json_name="newowner"];
+}
+
+message AlterOperatorStmt
+{
+  ObjectWithArgs opername = 1 [json_name="opername"];
+  repeated Node options = 2 [json_name="options"];
+}
+
+message AlterTypeStmt
+{
+  repeated Node type_name = 1 [json_name="typeName"];
+  repeated Node options = 2 [json_name="options"];
+}
+
+message RuleStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  string rulename = 2 [json_name="rulename"];
+  Node where_clause = 3 [json_name="whereClause"];
+  CmdType event = 4 [json_name="event"];
+  bool instead = 5 [json_name="instead"];
+  repeated Node actions = 6 [json_name="actions"];
+  bool replace = 7 [json_name="replace"];
+}
+
+message NotifyStmt
+{
+  string conditionname = 1 [json_name="conditionname"];
+  string payload = 2 [json_name="payload"];
+}
+
+message ListenStmt
+{
+  string conditionname = 1 [json_name="conditionname"];
+}
+
+message UnlistenStmt
+{
+  string conditionname = 1 [json_name="conditionname"];
+}
+
+message TransactionStmt
+{
+  TransactionStmtKind kind = 1 [json_name="kind"];
+  repeated Node options = 2 [json_name="options"];
+  string savepoint_name = 3 [json_name="savepoint_name"];
+  string gid = 4 [json_name="gid"];
+  bool chain = 5 [json_name="chain"];
+  int32 location = 6 [json_name="location"];
+}
+
+message CompositeTypeStmt
+{
+  RangeVar typevar = 1 [json_name="typevar"];
+  repeated Node coldeflist = 2 [json_name="coldeflist"];
+}
+
+message CreateEnumStmt
+{
+  repeated Node type_name = 1 [json_name="typeName"];
+  repeated Node vals = 2 [json_name="vals"];
+}
+
+message CreateRangeStmt
+{
+  repeated Node type_name = 1 [json_name="typeName"];
+  repeated Node params = 2 [json_name="params"];
+}
+
+message AlterEnumStmt
+{
+  repeated Node type_name = 1 [json_name="typeName"];
+  string old_val = 2 [json_name="oldVal"];
+  string new_val = 3 [json_name="newVal"];
+  string new_val_neighbor = 4 [json_name="newValNeighbor"];
+  bool new_val_is_after = 5 [json_name="newValIsAfter"];
+  bool skip_if_new_val_exists = 6 [json_name="skipIfNewValExists"];
+}
+
+message ViewStmt
+{
+  RangeVar view = 1 [json_name="view"];
+  repeated Node aliases = 2 [json_name="aliases"];
+  Node query = 3 [json_name="query"];
+  bool replace = 4 [json_name="replace"];
+  repeated Node options = 5 [json_name="options"];
+  ViewCheckOption with_check_option = 6 [json_name="withCheckOption"];
+}
+
+message LoadStmt
+{
+  string filename = 1 [json_name="filename"];
+}
+
+message CreatedbStmt
+{
+  string dbname = 1 [json_name="dbname"];
+  repeated Node options = 2 [json_name="options"];
+}
+
+message AlterDatabaseStmt
+{
+  string dbname = 1 [json_name="dbname"];
+  repeated Node options = 2 [json_name="options"];
+}
+
+message AlterDatabaseRefreshCollStmt
+{
+  string dbname = 1 [json_name="dbname"];
+}
+
+message AlterDatabaseSetStmt
+{
+  string dbname = 1 [json_name="dbname"];
+  VariableSetStmt setstmt = 2 [json_name="setstmt"];
+}
+
+message DropdbStmt
+{
+  string dbname = 1 [json_name="dbname"];
+  bool missing_ok = 2 [json_name="missing_ok"];
+  repeated Node options = 3 [json_name="options"];
+}
+
+message AlterSystemStmt
+{
+  VariableSetStmt setstmt = 1 [json_name="setstmt"];
+}
+
+message ClusterStmt
+{
+  RangeVar relation = 1 [json_name="relation"];
+  string indexname = 2 [json_name="indexname"];
+  repeated Node params = 3 [json_name="params"];
+}
+
+message VacuumStmt
+{
+  repeated Node options = 1 [json_name="options"];
+  repeated Node rels = 2 [json_name="rels"];
+  bool is_vacuumcmd = 3 [json_name="is_vacuumcmd"];
+}
+
+message VacuumRelation
+{
+  RangeVar relation = 1 [json_name="relation"];
+  uint32 oid = 2 [json_name="oid"];
+  repeated Node va_cols = 3 [json_name="va_cols"];
+}
+
+message ExplainStmt
+{
+  Node query = 1 [json_name="query"];
+  repeated Node options = 2 [json_name="options"];
+}
+
+message CreateTableAsStmt
+{
+  Node query = 1 [json_name="query"];
+  IntoClause into = 2 [json_name="into"];
+  ObjectType objtype = 3 [json_name="objtype"];
+  bool is_select_into = 4 [json_name="is_select_into"];
+  bool if_not_exists = 5 [json_name="if_not_exists"];
+}
+
+message RefreshMatViewStmt
+{
+  bool concurrent = 1 [json_name="concurrent"];
+  bool skip_data = 2 [json_name="skipData"];
+  RangeVar relation = 3 [json_name="relation"];
+}
+
+message CheckPointStmt
+{
+}
+
+message DiscardStmt
+{
+  DiscardMode target = 1 [json_name="target"];
+}
+
+message LockStmt
+{
+  repeated Node relations = 1 [json_name="relations"];
+  int32 mode = 2 [json_name="mode"];
+  bool nowait = 3 [json_name="nowait"];
+}
+
+message ConstraintsSetStmt
+{
+  repeated Node constraints = 1 [json_name="constraints"];
+  bool deferred = 2 [json_name="deferred"];
+}
+
+message ReindexStmt
+{
+  ReindexObjectType kind = 1 [json_name="kind"];
+  RangeVar relation = 2 [json_name="relation"];
+  string name = 3 [json_name="name"];
+  repeated Node params = 4 [json_name="params"];
+}
+
+message CreateConversionStmt
+{
+  repeated Node conversion_name = 1 [json_name="conversion_name"];
+  string for_encoding_name = 2 [json_name="for_encoding_name"];
+  string to_encoding_name = 3 [json_name="to_encoding_name"];
+  repeated Node func_name = 4 [json_name="func_name"];
+  bool def = 5 [json_name="def"];
+}
+
+message CreateCastStmt
+{
+  TypeName sourcetype = 1 [json_name="sourcetype"];
+  TypeName targettype = 2 [json_name="targettype"];
+  ObjectWithArgs func = 3 [json_name="func"];
+  CoercionContext context = 4 [json_name="context"];
+  bool inout = 5 [json_name="inout"];
+}
+
+message CreateTransformStmt
+{
+  bool replace = 1 [json_name="replace"];
+  TypeName type_name = 2 [json_name="type_name"];
+  string lang = 3 [json_name="lang"];
+  ObjectWithArgs fromsql = 4 [json_name="fromsql"];
+  ObjectWithArgs tosql = 5 [json_name="tosql"];
+}
+
+message PrepareStmt
+{
+  string name = 1 [json_name="name"];
+  repeated Node argtypes = 2 [json_name="argtypes"];
+  Node query = 3 [json_name="query"];
+}
+
+message ExecuteStmt
+{
+  string name = 1 [json_name="name"];
+  repeated Node params = 2 [json_name="params"];
+}
+
+message DeallocateStmt
+{
+  string name = 1 [json_name="name"];
+  bool isall = 2 [json_name="isall"];
+  int32 location = 3 [json_name="location"];
+}
+
+message DropOwnedStmt
+{
+  repeated Node roles = 1 [json_name="roles"];
+  DropBehavior behavior = 2 [json_name="behavior"];
+}
+
+message ReassignOwnedStmt
+{
+  repeated Node roles = 1 [json_name="roles"];
+  RoleSpec newrole = 2 [json_name="newrole"];
+}
+
+message AlterTSDictionaryStmt
+{
+  repeated Node dictname = 1 [json_name="dictname"];
+  repeated Node options = 2 [json_name="options"];
+}
+
+message AlterTSConfigurationStmt
+{
+  AlterTSConfigType kind = 1 [json_name="kind"];
+  repeated Node cfgname = 2 [json_name="cfgname"];
+  repeated Node tokentype = 3 [json_name="tokentype"];
+  repeated Node dicts = 4 [json_name="dicts"];
+  bool override = 5 [json_name="override"];
+  bool replace = 6 [json_name="replace"];
+  bool missing_ok = 7 [json_name="missing_ok"];
+}
+
+message PublicationTable
+{
+  RangeVar relation = 1 [json_name="relation"];
+  Node where_clause = 2 [json_name="whereClause"];
+  repeated Node columns = 3 [json_name="columns"];
+}
+
+message PublicationObjSpec
+{
+  PublicationObjSpecType pubobjtype = 1 [json_name="pubobjtype"];
+  string name = 2 [json_name="name"];
+  PublicationTable pubtable = 3 [json_name="pubtable"];
+  int32 location = 4 [json_name="location"];
+}
+
+message CreatePublicationStmt
+{
+  string pubname = 1 [json_name="pubname"];
+  repeated Node options = 2 [json_name="options"];
+  repeated Node pubobjects = 3 [json_name="pubobjects"];
+  bool for_all_tables = 4 [json_name="for_all_tables"];
+}
+
+message AlterPublicationStmt
+{
+  string pubname = 1 [json_name="pubname"];
+  repeated Node options = 2 [json_name="options"];
+  repeated Node pubobjects = 3 [json_name="pubobjects"];
+  bool for_all_tables = 4 [json_name="for_all_tables"];
+  AlterPublicationAction action = 5 [json_name="action"];
+}
+
+message CreateSubscriptionStmt
+{
+  string subname = 1 [json_name="subname"];
+  string conninfo = 2 [json_name="conninfo"];
+  repeated Node publication = 3 [json_name="publication"];
+  repeated Node options = 4 [json_name="options"];
+}
+
+message AlterSubscriptionStmt
+{
+  AlterSubscriptionType kind = 1 [json_name="kind"];
+  string subname = 2 [json_name="subname"];
+  string conninfo = 3 [json_name="conninfo"];
+  repeated Node publication = 4 [json_name="publication"];
+  repeated Node options = 5 [json_name="options"];
+}
+
+message DropSubscriptionStmt
+{
+  string subname = 1 [json_name="subname"];
+  bool missing_ok = 2 [json_name="missing_ok"];
+  DropBehavior behavior = 3 [json_name="behavior"];
+}
+
+enum QuerySource
+{
+  QUERY_SOURCE_UNDEFINED = 0;
+  QSRC_ORIGINAL = 1;
+  QSRC_PARSER = 2;
+  QSRC_INSTEAD_RULE = 3;
+  QSRC_QUAL_INSTEAD_RULE = 4;
+  QSRC_NON_INSTEAD_RULE = 5;
+}
+
+enum SortByDir
+{
+  SORT_BY_DIR_UNDEFINED = 0;
+  SORTBY_DEFAULT = 1;
+  SORTBY_ASC = 2;
+  SORTBY_DESC = 3;
+  SORTBY_USING = 4;
+}
+
+enum SortByNulls
+{
+  SORT_BY_NULLS_UNDEFINED = 0;
+  SORTBY_NULLS_DEFAULT = 1;
+  SORTBY_NULLS_FIRST = 2;
+  SORTBY_NULLS_LAST = 3;
+}
+
+enum SetQuantifier
+{
+  SET_QUANTIFIER_UNDEFINED = 0;
+  SET_QUANTIFIER_DEFAULT = 1;
+  SET_QUANTIFIER_ALL = 2;
+  SET_QUANTIFIER_DISTINCT = 3;
+}
+
+enum A_Expr_Kind
+{
+  A_EXPR_KIND_UNDEFINED = 0;
+  AEXPR_OP = 1;
+  AEXPR_OP_ANY = 2;
+  AEXPR_OP_ALL = 3;
+  AEXPR_DISTINCT = 4;
+  AEXPR_NOT_DISTINCT = 5;
+  AEXPR_NULLIF = 6;
+  AEXPR_IN = 7;
+  AEXPR_LIKE = 8;
+  AEXPR_ILIKE = 9;
+  AEXPR_SIMILAR = 10;
+  AEXPR_BETWEEN = 11;
+  AEXPR_NOT_BETWEEN = 12;
+  AEXPR_BETWEEN_SYM = 13;
+  AEXPR_NOT_BETWEEN_SYM = 14;
+}
+
+enum RoleSpecType
+{
+  ROLE_SPEC_TYPE_UNDEFINED = 0;
+  ROLESPEC_CSTRING = 1;
+  ROLESPEC_CURRENT_ROLE = 2;
+  ROLESPEC_CURRENT_USER = 3;
+  ROLESPEC_SESSION_USER = 4;
+  ROLESPEC_PUBLIC = 5;
+}
+
+enum TableLikeOption
+{
+  TABLE_LIKE_OPTION_UNDEFINED = 0;
+  CREATE_TABLE_LIKE_COMMENTS = 1;
+  CREATE_TABLE_LIKE_COMPRESSION = 2;
+  CREATE_TABLE_LIKE_CONSTRAINTS = 3;
+  CREATE_TABLE_LIKE_DEFAULTS = 4;
+  CREATE_TABLE_LIKE_GENERATED = 5;
+  CREATE_TABLE_LIKE_IDENTITY = 6;
+  CREATE_TABLE_LIKE_INDEXES = 7;
+  CREATE_TABLE_LIKE_STATISTICS = 8;
+  CREATE_TABLE_LIKE_STORAGE = 9;
+  CREATE_TABLE_LIKE_ALL = 10;
+}
+
+enum DefElemAction
+{
+  DEF_ELEM_ACTION_UNDEFINED = 0;
+  DEFELEM_UNSPEC = 1;
+  DEFELEM_SET = 2;
+  DEFELEM_ADD = 3;
+  DEFELEM_DROP = 4;
+}
+
+enum PartitionStrategy
+{
+  PARTITION_STRATEGY_UNDEFINED = 0;
+  PARTITION_STRATEGY_LIST = 1;
+  PARTITION_STRATEGY_RANGE = 2;
+  PARTITION_STRATEGY_HASH = 3;
+}
+
+enum PartitionRangeDatumKind
+{
+  PARTITION_RANGE_DATUM_KIND_UNDEFINED = 0;
+  PARTITION_RANGE_DATUM_MINVALUE = 1;
+  PARTITION_RANGE_DATUM_VALUE = 2;
+  PARTITION_RANGE_DATUM_MAXVALUE = 3;
+}
+
+enum RTEKind
+{
+  RTEKIND_UNDEFINED = 0;
+  RTE_RELATION = 1;
+  RTE_SUBQUERY = 2;
+  RTE_JOIN = 3;
+  RTE_FUNCTION = 4;
+  RTE_TABLEFUNC = 5;
+  RTE_VALUES = 6;
+  RTE_CTE = 7;
+  RTE_NAMEDTUPLESTORE = 8;
+  RTE_RESULT = 9;
+}
+
+enum WCOKind
+{
+  WCOKIND_UNDEFINED = 0;
+  WCO_VIEW_CHECK = 1;
+  WCO_RLS_INSERT_CHECK = 2;
+  WCO_RLS_UPDATE_CHECK = 3;
+  WCO_RLS_CONFLICT_CHECK = 4;
+  WCO_RLS_MERGE_UPDATE_CHECK = 5;
+  WCO_RLS_MERGE_DELETE_CHECK = 6;
+}
+
+enum GroupingSetKind
+{
+  GROUPING_SET_KIND_UNDEFINED = 0;
+  GROUPING_SET_EMPTY = 1;
+  GROUPING_SET_SIMPLE = 2;
+  GROUPING_SET_ROLLUP = 3;
+  GROUPING_SET_CUBE = 4;
+  GROUPING_SET_SETS = 5;
+}
+
+enum CTEMaterialize
+{
+  CTEMATERIALIZE_UNDEFINED = 0;
+  CTEMaterializeDefault = 1;
+  CTEMaterializeAlways = 2;
+  CTEMaterializeNever = 3;
+}
+
+enum JsonQuotes
+{
+  JSON_QUOTES_UNDEFINED = 0;
+  JS_QUOTES_UNSPEC = 1;
+  JS_QUOTES_KEEP = 2;
+  JS_QUOTES_OMIT = 3;
+}
+
+enum JsonTableColumnType
+{
+  JSON_TABLE_COLUMN_TYPE_UNDEFINED = 0;
+  JTC_FOR_ORDINALITY = 1;
+  JTC_REGULAR = 2;
+  JTC_EXISTS = 3;
+  JTC_FORMATTED = 4;
+  JTC_NESTED = 5;
+}
+
+enum SetOperation
+{
+  SET_OPERATION_UNDEFINED = 0;
+  SETOP_NONE = 1;
+  SETOP_UNION = 2;
+  SETOP_INTERSECT = 3;
+  SETOP_EXCEPT = 4;
+}
+
+enum ObjectType
+{
+  OBJECT_TYPE_UNDEFINED = 0;
+  OBJECT_ACCESS_METHOD = 1;
+  OBJECT_AGGREGATE = 2;
+  OBJECT_AMOP = 3;
+  OBJECT_AMPROC = 4;
+  OBJECT_ATTRIBUTE = 5;
+  OBJECT_CAST = 6;
+  OBJECT_COLUMN = 7;
+  OBJECT_COLLATION = 8;
+  OBJECT_CONVERSION = 9;
+  OBJECT_DATABASE = 10;
+  OBJECT_DEFAULT = 11;
+  OBJECT_DEFACL = 12;
+  OBJECT_DOMAIN = 13;
+  OBJECT_DOMCONSTRAINT = 14;
+  OBJECT_EVENT_TRIGGER = 15;
+  OBJECT_EXTENSION = 16;
+  OBJECT_FDW = 17;
+  OBJECT_FOREIGN_SERVER = 18;
+  OBJECT_FOREIGN_TABLE = 19;
+  OBJECT_FUNCTION = 20;
+  OBJECT_INDEX = 21;
+  OBJECT_LANGUAGE = 22;
+  OBJECT_LARGEOBJECT = 23;
+  OBJECT_MATVIEW = 24;
+  OBJECT_OPCLASS = 25;
+  OBJECT_OPERATOR = 26;
+  OBJECT_OPFAMILY = 27;
+  OBJECT_PARAMETER_ACL = 28;
+  OBJECT_POLICY = 29;
+  OBJECT_PROCEDURE = 30;
+  OBJECT_PUBLICATION = 31;
+  OBJECT_PUBLICATION_NAMESPACE = 32;
+  OBJECT_PUBLICATION_REL = 33;
+  OBJECT_ROLE = 34;
+  OBJECT_ROUTINE = 35;
+  OBJECT_RULE = 36;
+  OBJECT_SCHEMA = 37;
+  OBJECT_SEQUENCE = 38;
+  OBJECT_SUBSCRIPTION = 39;
+  OBJECT_STATISTIC_EXT = 40;
+  OBJECT_TABCONSTRAINT = 41;
+  OBJECT_TABLE = 42;
+  OBJECT_TABLESPACE = 43;
+  OBJECT_TRANSFORM = 44;
+  OBJECT_TRIGGER = 45;
+  OBJECT_TSCONFIGURATION = 46;
+  OBJECT_TSDICTIONARY = 47;
+  OBJECT_TSPARSER = 48;
+  OBJECT_TSTEMPLATE = 49;
+  OBJECT_TYPE = 50;
+  OBJECT_USER_MAPPING = 51;
+  OBJECT_VIEW = 52;
+}
+
+enum DropBehavior
+{
+  DROP_BEHAVIOR_UNDEFINED = 0;
+  DROP_RESTRICT = 1;
+  DROP_CASCADE = 2;
+}
+
+enum AlterTableType
+{
+  ALTER_TABLE_TYPE_UNDEFINED = 0;
+  AT_AddColumn = 1;
+  AT_AddColumnToView = 2;
+  AT_ColumnDefault = 3;
+  AT_CookedColumnDefault = 4;
+  AT_DropNotNull = 5;
+  AT_SetNotNull = 6;
+  AT_SetExpression = 7;
+  AT_DropExpression = 8;
+  AT_CheckNotNull = 9;
+  AT_SetStatistics = 10;
+  AT_SetOptions = 11;
+  AT_ResetOptions = 12;
+  AT_SetStorage = 13;
+  AT_SetCompression = 14;
+  AT_DropColumn = 15;
+  AT_AddIndex = 16;
+  AT_ReAddIndex = 17;
+  AT_AddConstraint = 18;
+  AT_ReAddConstraint = 19;
+  AT_ReAddDomainConstraint = 20;
+  AT_AlterConstraint = 21;
+  AT_ValidateConstraint = 22;
+  AT_AddIndexConstraint = 23;
+  AT_DropConstraint = 24;
+  AT_ReAddComment = 25;
+  AT_AlterColumnType = 26;
+  AT_AlterColumnGenericOptions = 27;
+  AT_ChangeOwner = 28;
+  AT_ClusterOn = 29;
+  AT_DropCluster = 30;
+  AT_SetLogged = 31;
+  AT_SetUnLogged = 32;
+  AT_DropOids = 33;
+  AT_SetAccessMethod = 34;
+  AT_SetTableSpace = 35;
+  AT_SetRelOptions = 36;
+  AT_ResetRelOptions = 37;
+  AT_ReplaceRelOptions = 38;
+  AT_EnableTrig = 39;
+  AT_EnableAlwaysTrig = 40;
+  AT_EnableReplicaTrig = 41;
+  AT_DisableTrig = 42;
+  AT_EnableTrigAll = 43;
+  AT_DisableTrigAll = 44;
+  AT_EnableTrigUser = 45;
+  AT_DisableTrigUser = 46;
+  AT_EnableRule = 47;
+  AT_EnableAlwaysRule = 48;
+  AT_EnableReplicaRule = 49;
+  AT_DisableRule = 50;
+  AT_AddInherit = 51;
+  AT_DropInherit = 52;
+  AT_AddOf = 53;
+  AT_DropOf = 54;
+  AT_ReplicaIdentity = 55;
+  AT_EnableRowSecurity = 56;
+  AT_DisableRowSecurity = 57;
+  AT_ForceRowSecurity = 58;
+  AT_NoForceRowSecurity = 59;
+  AT_GenericOptions = 60;
+  AT_AttachPartition = 61;
+  AT_DetachPartition = 62;
+  AT_DetachPartitionFinalize = 63;
+  AT_AddIdentity = 64;
+  AT_SetIdentity = 65;
+  AT_DropIdentity = 66;
+  AT_ReAddStatistics = 67;
+}
+
+enum GrantTargetType
+{
+  GRANT_TARGET_TYPE_UNDEFINED = 0;
+  ACL_TARGET_OBJECT = 1;
+  ACL_TARGET_ALL_IN_SCHEMA = 2;
+  ACL_TARGET_DEFAULTS = 3;
+}
+
+enum VariableSetKind
+{
+  VARIABLE_SET_KIND_UNDEFINED = 0;
+  VAR_SET_VALUE = 1;
+  VAR_SET_DEFAULT = 2;
+  VAR_SET_CURRENT = 3;
+  VAR_SET_MULTI = 4;
+  VAR_RESET = 5;
+  VAR_RESET_ALL = 6;
+}
+
+enum ConstrType
+{
+  CONSTR_TYPE_UNDEFINED = 0;
+  CONSTR_NULL = 1;
+  CONSTR_NOTNULL = 2;
+  CONSTR_DEFAULT = 3;
+  CONSTR_IDENTITY = 4;
+  CONSTR_GENERATED = 5;
+  CONSTR_CHECK = 6;
+  CONSTR_PRIMARY = 7;
+  CONSTR_UNIQUE = 8;
+  CONSTR_EXCLUSION = 9;
+  CONSTR_FOREIGN = 10;
+  CONSTR_ATTR_DEFERRABLE = 11;
+  CONSTR_ATTR_NOT_DEFERRABLE = 12;
+  CONSTR_ATTR_DEFERRED = 13;
+  CONSTR_ATTR_IMMEDIATE = 14;
+}
+
+enum ImportForeignSchemaType
+{
+  IMPORT_FOREIGN_SCHEMA_TYPE_UNDEFINED = 0;
+  FDW_IMPORT_SCHEMA_ALL = 1;
+  FDW_IMPORT_SCHEMA_LIMIT_TO = 2;
+  FDW_IMPORT_SCHEMA_EXCEPT = 3;
+}
+
+enum RoleStmtType
+{
+  ROLE_STMT_TYPE_UNDEFINED = 0;
+  ROLESTMT_ROLE = 1;
+  ROLESTMT_USER = 2;
+  ROLESTMT_GROUP = 3;
+}
+
+enum FetchDirection
+{
+  FETCH_DIRECTION_UNDEFINED = 0;
+  FETCH_FORWARD = 1;
+  FETCH_BACKWARD = 2;
+  FETCH_ABSOLUTE = 3;
+  FETCH_RELATIVE = 4;
+}
+
+enum FunctionParameterMode
+{
+  FUNCTION_PARAMETER_MODE_UNDEFINED = 0;
+  FUNC_PARAM_IN = 1;
+  FUNC_PARAM_OUT = 2;
+  FUNC_PARAM_INOUT = 3;
+  FUNC_PARAM_VARIADIC = 4;
+  FUNC_PARAM_TABLE = 5;
+  FUNC_PARAM_DEFAULT = 6;
+}
+
+enum TransactionStmtKind
+{
+  TRANSACTION_STMT_KIND_UNDEFINED = 0;
+  TRANS_STMT_BEGIN = 1;
+  TRANS_STMT_START = 2;
+  TRANS_STMT_COMMIT = 3;
+  TRANS_STMT_ROLLBACK = 4;
+  TRANS_STMT_SAVEPOINT = 5;
+  TRANS_STMT_RELEASE = 6;
+  TRANS_STMT_ROLLBACK_TO = 7;
+  TRANS_STMT_PREPARE = 8;
+  TRANS_STMT_COMMIT_PREPARED = 9;
+  TRANS_STMT_ROLLBACK_PREPARED = 10;
+}
+
+enum ViewCheckOption
+{
+  VIEW_CHECK_OPTION_UNDEFINED = 0;
+  NO_CHECK_OPTION = 1;
+  LOCAL_CHECK_OPTION = 2;
+  CASCADED_CHECK_OPTION = 3;
+}
+
+enum DiscardMode
+{
+  DISCARD_MODE_UNDEFINED = 0;
+  DISCARD_ALL = 1;
+  DISCARD_PLANS = 2;
+  DISCARD_SEQUENCES = 3;
+  DISCARD_TEMP = 4;
+}
+
+enum ReindexObjectType
+{
+  REINDEX_OBJECT_TYPE_UNDEFINED = 0;
+  REINDEX_OBJECT_INDEX = 1;
+  REINDEX_OBJECT_TABLE = 2;
+  REINDEX_OBJECT_SCHEMA = 3;
+  REINDEX_OBJECT_SYSTEM = 4;
+  REINDEX_OBJECT_DATABASE = 5;
+}
+
+enum AlterTSConfigType
+{
+  ALTER_TSCONFIG_TYPE_UNDEFINED = 0;
+  ALTER_TSCONFIG_ADD_MAPPING = 1;
+  ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN = 2;
+  ALTER_TSCONFIG_REPLACE_DICT = 3;
+  ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN = 4;
+  ALTER_TSCONFIG_DROP_MAPPING = 5;
+}
+
+enum PublicationObjSpecType
+{
+  PUBLICATION_OBJ_SPEC_TYPE_UNDEFINED = 0;
+  PUBLICATIONOBJ_TABLE = 1;
+  PUBLICATIONOBJ_TABLES_IN_SCHEMA = 2;
+  PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA = 3;
+  PUBLICATIONOBJ_CONTINUATION = 4;
+}
+
+enum AlterPublicationAction
+{
+  ALTER_PUBLICATION_ACTION_UNDEFINED = 0;
+  AP_AddObjects = 1;
+  AP_DropObjects = 2;
+  AP_SetObjects = 3;
+}
+
+enum AlterSubscriptionType
+{
+  ALTER_SUBSCRIPTION_TYPE_UNDEFINED = 0;
+  ALTER_SUBSCRIPTION_OPTIONS = 1;
+  ALTER_SUBSCRIPTION_CONNECTION = 2;
+  ALTER_SUBSCRIPTION_SET_PUBLICATION = 3;
+  ALTER_SUBSCRIPTION_ADD_PUBLICATION = 4;
+  ALTER_SUBSCRIPTION_DROP_PUBLICATION = 5;
+  ALTER_SUBSCRIPTION_REFRESH = 6;
+  ALTER_SUBSCRIPTION_ENABLED = 7;
+  ALTER_SUBSCRIPTION_SKIP = 8;
+}
+
+enum OverridingKind
+{
+  OVERRIDING_KIND_UNDEFINED = 0;
+  OVERRIDING_NOT_SET = 1;
+  OVERRIDING_USER_VALUE = 2;
+  OVERRIDING_SYSTEM_VALUE = 3;
+}
+
+enum OnCommitAction
+{
+  ON_COMMIT_ACTION_UNDEFINED = 0;
+  ONCOMMIT_NOOP = 1;
+  ONCOMMIT_PRESERVE_ROWS = 2;
+  ONCOMMIT_DELETE_ROWS = 3;
+  ONCOMMIT_DROP = 4;
+}
+
+enum TableFuncType
+{
+  TABLE_FUNC_TYPE_UNDEFINED = 0;
+  TFT_XMLTABLE = 1;
+  TFT_JSON_TABLE = 2;
+}
+
+enum ParamKind
+{
+  PARAM_KIND_UNDEFINED = 0;
+  PARAM_EXTERN = 1;
+  PARAM_EXEC = 2;
+  PARAM_SUBLINK = 3;
+  PARAM_MULTIEXPR = 4;
+}
+
+enum CoercionContext
+{
+  COERCION_CONTEXT_UNDEFINED = 0;
+  COERCION_IMPLICIT = 1;
+  COERCION_ASSIGNMENT = 2;
+  COERCION_PLPGSQL = 3;
+  COERCION_EXPLICIT = 4;
+}
+
+enum CoercionForm
+{
+  COERCION_FORM_UNDEFINED = 0;
+  COERCE_EXPLICIT_CALL = 1;
+  COERCE_EXPLICIT_CAST = 2;
+  COERCE_IMPLICIT_CAST = 3;
+  COERCE_SQL_SYNTAX = 4;
+}
+
+enum BoolExprType
+{
+  BOOL_EXPR_TYPE_UNDEFINED = 0;
+  AND_EXPR = 1;
+  OR_EXPR = 2;
+  NOT_EXPR = 3;
+}
+
+enum SubLinkType
+{
+  SUB_LINK_TYPE_UNDEFINED = 0;
+  EXISTS_SUBLINK = 1;
+  ALL_SUBLINK = 2;
+  ANY_SUBLINK = 3;
+  ROWCOMPARE_SUBLINK = 4;
+  EXPR_SUBLINK = 5;
+  MULTIEXPR_SUBLINK = 6;
+  ARRAY_SUBLINK = 7;
+  CTE_SUBLINK = 8;
+}
+
+enum RowCompareType
+{
+  ROW_COMPARE_TYPE_UNDEFINED = 0;
+  ROWCOMPARE_LT = 1;
+  ROWCOMPARE_LE = 2;
+  ROWCOMPARE_EQ = 3;
+  ROWCOMPARE_GE = 4;
+  ROWCOMPARE_GT = 5;
+  ROWCOMPARE_NE = 6;
+}
+
+enum MinMaxOp
+{
+  MIN_MAX_OP_UNDEFINED = 0;
+  IS_GREATEST = 1;
+  IS_LEAST = 2;
+}
+
+enum SQLValueFunctionOp
+{
+  SQLVALUE_FUNCTION_OP_UNDEFINED = 0;
+  SVFOP_CURRENT_DATE = 1;
+  SVFOP_CURRENT_TIME = 2;
+  SVFOP_CURRENT_TIME_N = 3;
+  SVFOP_CURRENT_TIMESTAMP = 4;
+  SVFOP_CURRENT_TIMESTAMP_N = 5;
+  SVFOP_LOCALTIME = 6;
+  SVFOP_LOCALTIME_N = 7;
+  SVFOP_LOCALTIMESTAMP = 8;
+  SVFOP_LOCALTIMESTAMP_N = 9;
+  SVFOP_CURRENT_ROLE = 10;
+  SVFOP_CURRENT_USER = 11;
+  SVFOP_USER = 12;
+  SVFOP_SESSION_USER = 13;
+  SVFOP_CURRENT_CATALOG = 14;
+  SVFOP_CURRENT_SCHEMA = 15;
+}
+
+enum XmlExprOp
+{
+  XML_EXPR_OP_UNDEFINED = 0;
+  IS_XMLCONCAT = 1;
+  IS_XMLELEMENT = 2;
+  IS_XMLFOREST = 3;
+  IS_XMLPARSE = 4;
+  IS_XMLPI = 5;
+  IS_XMLROOT = 6;
+  IS_XMLSERIALIZE = 7;
+  IS_DOCUMENT = 8;
+}
+
+enum XmlOptionType
+{
+  XML_OPTION_TYPE_UNDEFINED = 0;
+  XMLOPTION_DOCUMENT = 1;
+  XMLOPTION_CONTENT = 2;
+}
+
+enum JsonEncoding
+{
+  JSON_ENCODING_UNDEFINED = 0;
+  JS_ENC_DEFAULT = 1;
+  JS_ENC_UTF8 = 2;
+  JS_ENC_UTF16 = 3;
+  JS_ENC_UTF32 = 4;
+}
+
+enum JsonFormatType
+{
+  JSON_FORMAT_TYPE_UNDEFINED = 0;
+  JS_FORMAT_DEFAULT = 1;
+  JS_FORMAT_JSON = 2;
+  JS_FORMAT_JSONB = 3;
+}
+
+enum JsonConstructorType
+{
+  JSON_CONSTRUCTOR_TYPE_UNDEFINED = 0;
+  JSCTOR_JSON_OBJECT = 1;
+  JSCTOR_JSON_ARRAY = 2;
+  JSCTOR_JSON_OBJECTAGG = 3;
+  JSCTOR_JSON_ARRAYAGG = 4;
+  JSCTOR_JSON_PARSE = 5;
+  JSCTOR_JSON_SCALAR = 6;
+  JSCTOR_JSON_SERIALIZE = 7;
+}
+
+enum JsonValueType
+{
+  JSON_VALUE_TYPE_UNDEFINED = 0;
+  JS_TYPE_ANY = 1;
+  JS_TYPE_OBJECT = 2;
+  JS_TYPE_ARRAY = 3;
+  JS_TYPE_SCALAR = 4;
+}
+
+enum JsonWrapper
+{
+  JSON_WRAPPER_UNDEFINED = 0;
+  JSW_UNSPEC = 1;
+  JSW_NONE = 2;
+  JSW_CONDITIONAL = 3;
+  JSW_UNCONDITIONAL = 4;
+}
+
+enum JsonBehaviorType
+{
+  JSON_BEHAVIOR_TYPE_UNDEFINED = 0;
+  JSON_BEHAVIOR_NULL = 1;
+  JSON_BEHAVIOR_ERROR = 2;
+  JSON_BEHAVIOR_EMPTY = 3;
+  JSON_BEHAVIOR_TRUE = 4;
+  JSON_BEHAVIOR_FALSE = 5;
+  JSON_BEHAVIOR_UNKNOWN = 6;
+  JSON_BEHAVIOR_EMPTY_ARRAY = 7;
+  JSON_BEHAVIOR_EMPTY_OBJECT = 8;
+  JSON_BEHAVIOR_DEFAULT = 9;
+}
+
+enum JsonExprOp
+{
+  JSON_EXPR_OP_UNDEFINED = 0;
+  JSON_EXISTS_OP = 1;
+  JSON_QUERY_OP = 2;
+  JSON_VALUE_OP = 3;
+  JSON_TABLE_OP = 4;
+}
+
+enum NullTestType
+{
+  NULL_TEST_TYPE_UNDEFINED = 0;
+  IS_NULL = 1;
+  IS_NOT_NULL = 2;
+}
+
+enum BoolTestType
+{
+  BOOL_TEST_TYPE_UNDEFINED = 0;
+  IS_TRUE = 1;
+  IS_NOT_TRUE = 2;
+  IS_FALSE = 3;
+  IS_NOT_FALSE = 4;
+  IS_UNKNOWN = 5;
+  IS_NOT_UNKNOWN = 6;
+}
+
+enum MergeMatchKind
+{
+  MERGE_MATCH_KIND_UNDEFINED = 0;
+  MERGE_WHEN_MATCHED = 1;
+  MERGE_WHEN_NOT_MATCHED_BY_SOURCE = 2;
+  MERGE_WHEN_NOT_MATCHED_BY_TARGET = 3;
+}
+
+enum CmdType
+{
+  CMD_TYPE_UNDEFINED = 0;
+  CMD_UNKNOWN = 1;
+  CMD_SELECT = 2;
+  CMD_UPDATE = 3;
+  CMD_INSERT = 4;
+  CMD_DELETE = 5;
+  CMD_MERGE = 6;
+  CMD_UTILITY = 7;
+  CMD_NOTHING = 8;
+}
+
+enum JoinType
+{
+  JOIN_TYPE_UNDEFINED = 0;
+  JOIN_INNER = 1;
+  JOIN_LEFT = 2;
+  JOIN_FULL = 3;
+  JOIN_RIGHT = 4;
+  JOIN_SEMI = 5;
+  JOIN_ANTI = 6;
+  JOIN_RIGHT_ANTI = 7;
+  JOIN_UNIQUE_OUTER = 8;
+  JOIN_UNIQUE_INNER = 9;
+}
+
+enum AggStrategy
+{
+  AGG_STRATEGY_UNDEFINED = 0;
+  AGG_PLAIN = 1;
+  AGG_SORTED = 2;
+  AGG_HASHED = 3;
+  AGG_MIXED = 4;
+}
+
+enum AggSplit
+{
+  AGG_SPLIT_UNDEFINED = 0;
+  AGGSPLIT_SIMPLE = 1;
+  AGGSPLIT_INITIAL_SERIAL = 2;
+  AGGSPLIT_FINAL_DESERIAL = 3;
+}
+
+enum SetOpCmd
+{
+  SET_OP_CMD_UNDEFINED = 0;
+  SETOPCMD_INTERSECT = 1;
+  SETOPCMD_INTERSECT_ALL = 2;
+  SETOPCMD_EXCEPT = 3;
+  SETOPCMD_EXCEPT_ALL = 4;
+}
+
+enum SetOpStrategy
+{
+  SET_OP_STRATEGY_UNDEFINED = 0;
+  SETOP_SORTED = 1;
+  SETOP_HASHED = 2;
+}
+
+enum OnConflictAction
+{
+  ON_CONFLICT_ACTION_UNDEFINED = 0;
+  ONCONFLICT_NONE = 1;
+  ONCONFLICT_NOTHING = 2;
+  ONCONFLICT_UPDATE = 3;
+}
+
+enum LimitOption
+{
+  LIMIT_OPTION_UNDEFINED = 0;
+  LIMIT_OPTION_DEFAULT = 1;
+  LIMIT_OPTION_COUNT = 2;
+  LIMIT_OPTION_WITH_TIES = 3;
+}
+
+enum LockClauseStrength
+{
+  LOCK_CLAUSE_STRENGTH_UNDEFINED = 0;
+  LCS_NONE = 1;
+  LCS_FORKEYSHARE = 2;
+  LCS_FORSHARE = 3;
+  LCS_FORNOKEYUPDATE = 4;
+  LCS_FORUPDATE = 5;
+}
+
+enum LockWaitPolicy
+{
+  LOCK_WAIT_POLICY_UNDEFINED = 0;
+  LockWaitBlock = 1;
+  LockWaitSkip = 2;
+  LockWaitError = 3;
+}
+
+enum LockTupleMode
+{
+  LOCK_TUPLE_MODE_UNDEFINED = 0;
+  LockTupleKeyShare = 1;
+  LockTupleShare = 2;
+  LockTupleNoKeyExclusive = 3;
+  LockTupleExclusive = 4;
+}
+
+message ScanToken {
+  int32 start = 1;
+  int32 end = 2;
+  Token token = 4;
+  KeywordKind keyword_kind = 5;
+}
+
+enum KeywordKind {
+  NO_KEYWORD = 0;
+  UNRESERVED_KEYWORD = 1;
+  COL_NAME_KEYWORD = 2;
+  TYPE_FUNC_NAME_KEYWORD = 3;
+  RESERVED_KEYWORD = 4;
+}
+
+enum Token {
+  NUL = 0;
+  // Single-character tokens that are returned 1:1 (identical with "self" list in scan.l)
+  // Either supporting syntax, or single-character operators (some can be both)
+  // Also see https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-SYNTAX-SPECIAL-CHARS
+  ASCII_36 = 36; // "$"
+  ASCII_37 = 37; // "%"
+  ASCII_40 = 40; // "("
+  ASCII_41 = 41; // ")"
+  ASCII_42 = 42; // "*"
+  ASCII_43 = 43; // "+"
+  ASCII_44 = 44; // ","
+  ASCII_45 = 45; // "-"
+  ASCII_46 = 46; // "."
+  ASCII_47 = 47; // "/"
+  ASCII_58 = 58; // ":"
+  ASCII_59 = 59; // ";"
+  ASCII_60 = 60; // "<"
+  ASCII_61 = 61; // "="
+  ASCII_62 = 62; // ">"
+  ASCII_63 = 63; // "?"
+  ASCII_91 = 91; // "["
+  ASCII_92 = 92; // "\"
+  ASCII_93 = 93; // "]"
+  ASCII_94 = 94; // "^"
+  // Named tokens in scan.l
+  IDENT = 258;
+  UIDENT = 259;
+  FCONST = 260;
+  SCONST = 261;
+  USCONST = 262;
+  BCONST = 263;
+  XCONST = 264;
+  Op = 265;
+  ICONST = 266;
+  PARAM = 267;
+  TYPECAST = 268;
+  DOT_DOT = 269;
+  COLON_EQUALS = 270;
+  EQUALS_GREATER = 271;
+  LESS_EQUALS = 272;
+  GREATER_EQUALS = 273;
+  NOT_EQUALS = 274;
+  SQL_COMMENT = 275;
+  C_COMMENT = 276;
+  ABORT_P = 277;
+  ABSENT = 278;
+  ABSOLUTE_P = 279;
+  ACCESS = 280;
+  ACTION = 281;
+  ADD_P = 282;
+  ADMIN = 283;
+  AFTER = 284;
+  AGGREGATE = 285;
+  ALL = 286;
+  ALSO = 287;
+  ALTER = 288;
+  ALWAYS = 289;
+  ANALYSE = 290;
+  ANALYZE = 291;
+  AND = 292;
+  ANY = 293;
+  ARRAY = 294;
+  AS = 295;
+  ASC = 296;
+  ASENSITIVE = 297;
+  ASSERTION = 298;
+  ASSIGNMENT = 299;
+  ASYMMETRIC = 300;
+  ATOMIC = 301;
+  AT = 302;
+  ATTACH = 303;
+  ATTRIBUTE = 304;
+  AUTHORIZATION = 305;
+  BACKWARD = 306;
+  BEFORE = 307;
+  BEGIN_P = 308;
+  BETWEEN = 309;
+  BIGINT = 310;
+  BINARY = 311;
+  BIT = 312;
+  BOOLEAN_P = 313;
+  BOTH = 314;
+  BREADTH = 315;
+  BY = 316;
+  CACHE = 317;
+  CALL = 318;
+  CALLED = 319;
+  CASCADE = 320;
+  CASCADED = 321;
+  CASE = 322;
+  CAST = 323;
+  CATALOG_P = 324;
+  CHAIN = 325;
+  CHAR_P = 326;
+  CHARACTER = 327;
+  CHARACTERISTICS = 328;
+  CHECK = 329;
+  CHECKPOINT = 330;
+  CLASS = 331;
+  CLOSE = 332;
+  CLUSTER = 333;
+  COALESCE = 334;
+  COLLATE = 335;
+  COLLATION = 336;
+  COLUMN = 337;
+  COLUMNS = 338;
+  COMMENT = 339;
+  COMMENTS = 340;
+  COMMIT = 341;
+  COMMITTED = 342;
+  COMPRESSION = 343;
+  CONCURRENTLY = 344;
+  CONDITIONAL = 345;
+  CONFIGURATION = 346;
+  CONFLICT = 347;
+  CONNECTION = 348;
+  CONSTRAINT = 349;
+  CONSTRAINTS = 350;
+  CONTENT_P = 351;
+  CONTINUE_P = 352;
+  CONVERSION_P = 353;
+  COPY = 354;
+  COST = 355;
+  CREATE = 356;
+  CROSS = 357;
+  CSV = 358;
+  CUBE = 359;
+  CURRENT_P = 360;
+  CURRENT_CATALOG = 361;
+  CURRENT_DATE = 362;
+  CURRENT_ROLE = 363;
+  CURRENT_SCHEMA = 364;
+  CURRENT_TIME = 365;
+  CURRENT_TIMESTAMP = 366;
+  CURRENT_USER = 367;
+  CURSOR = 368;
+  CYCLE = 369;
+  DATA_P = 370;
+  DATABASE = 371;
+  DAY_P = 372;
+  DEALLOCATE = 373;
+  DEC = 374;
+  DECIMAL_P = 375;
+  DECLARE = 376;
+  DEFAULT = 377;
+  DEFAULTS = 378;
+  DEFERRABLE = 379;
+  DEFERRED = 380;
+  DEFINER = 381;
+  DELETE_P = 382;
+  DELIMITER = 383;
+  DELIMITERS = 384;
+  DEPENDS = 385;
+  DEPTH = 386;
+  DESC = 387;
+  DETACH = 388;
+  DICTIONARY = 389;
+  DISABLE_P = 390;
+  DISCARD = 391;
+  DISTINCT = 392;
+  DO = 393;
+  DOCUMENT_P = 394;
+  DOMAIN_P = 395;
+  DOUBLE_P = 396;
+  DROP = 397;
+  EACH = 398;
+  ELSE = 399;
+  EMPTY_P = 400;
+  ENABLE_P = 401;
+  ENCODING = 402;
+  ENCRYPTED = 403;
+  END_P = 404;
+  ENUM_P = 405;
+  ERROR_P = 406;
+  ESCAPE = 407;
+  EVENT = 408;
+  EXCEPT = 409;
+  EXCLUDE = 410;
+  EXCLUDING = 411;
+  EXCLUSIVE = 412;
+  EXECUTE = 413;
+  EXISTS = 414;
+  EXPLAIN = 415;
+  EXPRESSION = 416;
+  EXTENSION = 417;
+  EXTERNAL = 418;
+  EXTRACT = 419;
+  FALSE_P = 420;
+  FAMILY = 421;
+  FETCH = 422;
+  FILTER = 423;
+  FINALIZE = 424;
+  FIRST_P = 425;
+  FLOAT_P = 426;
+  FOLLOWING = 427;
+  FOR = 428;
+  FORCE = 429;
+  FOREIGN = 430;
+  FORMAT = 431;
+  FORWARD = 432;
+  FREEZE = 433;
+  FROM = 434;
+  FULL = 435;
+  FUNCTION = 436;
+  FUNCTIONS = 437;
+  GENERATED = 438;
+  GLOBAL = 439;
+  GRANT = 440;
+  GRANTED = 441;
+  GREATEST = 442;
+  GROUP_P = 443;
+  GROUPING = 444;
+  GROUPS = 445;
+  HANDLER = 446;
+  HAVING = 447;
+  HEADER_P = 448;
+  HOLD = 449;
+  HOUR_P = 450;
+  IDENTITY_P = 451;
+  IF_P = 452;
+  ILIKE = 453;
+  IMMEDIATE = 454;
+  IMMUTABLE = 455;
+  IMPLICIT_P = 456;
+  IMPORT_P = 457;
+  IN_P = 458;
+  INCLUDE = 459;
+  INCLUDING = 460;
+  INCREMENT = 461;
+  INDENT = 462;
+  INDEX = 463;
+  INDEXES = 464;
+  INHERIT = 465;
+  INHERITS = 466;
+  INITIALLY = 467;
+  INLINE_P = 468;
+  INNER_P = 469;
+  INOUT = 470;
+  INPUT_P = 471;
+  INSENSITIVE = 472;
+  INSERT = 473;
+  INSTEAD = 474;
+  INT_P = 475;
+  INTEGER = 476;
+  INTERSECT = 477;
+  INTERVAL = 478;
+  INTO = 479;
+  INVOKER = 480;
+  IS = 481;
+  ISNULL = 482;
+  ISOLATION = 483;
+  JOIN = 484;
+  JSON = 485;
+  JSON_ARRAY = 486;
+  JSON_ARRAYAGG = 487;
+  JSON_EXISTS = 488;
+  JSON_OBJECT = 489;
+  JSON_OBJECTAGG = 490;
+  JSON_QUERY = 491;
+  JSON_SCALAR = 492;
+  JSON_SERIALIZE = 493;
+  JSON_TABLE = 494;
+  JSON_VALUE = 495;
+  KEEP = 496;
+  KEY = 497;
+  KEYS = 498;
+  LABEL = 499;
+  LANGUAGE = 500;
+  LARGE_P = 501;
+  LAST_P = 502;
+  LATERAL_P = 503;
+  LEADING = 504;
+  LEAKPROOF = 505;
+  LEAST = 506;
+  LEFT = 507;
+  LEVEL = 508;
+  LIKE = 509;
+  LIMIT = 510;
+  LISTEN = 511;
+  LOAD = 512;
+  LOCAL = 513;
+  LOCALTIME = 514;
+  LOCALTIMESTAMP = 515;
+  LOCATION = 516;
+  LOCK_P = 517;
+  LOCKED = 518;
+  LOGGED = 519;
+  MAPPING = 520;
+  MATCH = 521;
+  MATCHED = 522;
+  MATERIALIZED = 523;
+  MAXVALUE = 524;
+  MERGE = 525;
+  MERGE_ACTION = 526;
+  METHOD = 527;
+  MINUTE_P = 528;
+  MINVALUE = 529;
+  MODE = 530;
+  MONTH_P = 531;
+  MOVE = 532;
+  NAME_P = 533;
+  NAMES = 534;
+  NATIONAL = 535;
+  NATURAL = 536;
+  NCHAR = 537;
+  NESTED = 538;
+  NEW = 539;
+  NEXT = 540;
+  NFC = 541;
+  NFD = 542;
+  NFKC = 543;
+  NFKD = 544;
+  NO = 545;
+  NONE = 546;
+  NORMALIZE = 547;
+  NORMALIZED = 548;
+  NOT = 549;
+  NOTHING = 550;
+  NOTIFY = 551;
+  NOTNULL = 552;
+  NOWAIT = 553;
+  NULL_P = 554;
+  NULLIF = 555;
+  NULLS_P = 556;
+  NUMERIC = 557;
+  OBJECT_P = 558;
+  OF = 559;
+  OFF = 560;
+  OFFSET = 561;
+  OIDS = 562;
+  OLD = 563;
+  OMIT = 564;
+  ON = 565;
+  ONLY = 566;
+  OPERATOR = 567;
+  OPTION = 568;
+  OPTIONS = 569;
+  OR = 570;
+  ORDER = 571;
+  ORDINALITY = 572;
+  OTHERS = 573;
+  OUT_P = 574;
+  OUTER_P = 575;
+  OVER = 576;
+  OVERLAPS = 577;
+  OVERLAY = 578;
+  OVERRIDING = 579;
+  OWNED = 580;
+  OWNER = 581;
+  PARALLEL = 582;
+  PARAMETER = 583;
+  PARSER = 584;
+  PARTIAL = 585;
+  PARTITION = 586;
+  PASSING = 587;
+  PASSWORD = 588;
+  PATH = 589;
+  PLACING = 590;
+  PLAN = 591;
+  PLANS = 592;
+  POLICY = 593;
+  POSITION = 594;
+  PRECEDING = 595;
+  PRECISION = 596;
+  PRESERVE = 597;
+  PREPARE = 598;
+  PREPARED = 599;
+  PRIMARY = 600;
+  PRIOR = 601;
+  PRIVILEGES = 602;
+  PROCEDURAL = 603;
+  PROCEDURE = 604;
+  PROCEDURES = 605;
+  PROGRAM = 606;
+  PUBLICATION = 607;
+  QUOTE = 608;
+  QUOTES = 609;
+  RANGE = 610;
+  READ = 611;
+  REAL = 612;
+  REASSIGN = 613;
+  RECHECK = 614;
+  RECURSIVE = 615;
+  REF_P = 616;
+  REFERENCES = 617;
+  REFERENCING = 618;
+  REFRESH = 619;
+  REINDEX = 620;
+  RELATIVE_P = 621;
+  RELEASE = 622;
+  RENAME = 623;
+  REPEATABLE = 624;
+  REPLACE = 625;
+  REPLICA = 626;
+  RESET = 627;
+  RESTART = 628;
+  RESTRICT = 629;
+  RETURN = 630;
+  RETURNING = 631;
+  RETURNS = 632;
+  REVOKE = 633;
+  RIGHT = 634;
+  ROLE = 635;
+  ROLLBACK = 636;
+  ROLLUP = 637;
+  ROUTINE = 638;
+  ROUTINES = 639;
+  ROW = 640;
+  ROWS = 641;
+  RULE = 642;
+  SAVEPOINT = 643;
+  SCALAR = 644;
+  SCHEMA = 645;
+  SCHEMAS = 646;
+  SCROLL = 647;
+  SEARCH = 648;
+  SECOND_P = 649;
+  SECURITY = 650;
+  SELECT = 651;
+  SEQUENCE = 652;
+  SEQUENCES = 653;
+  SERIALIZABLE = 654;
+  SERVER = 655;
+  SESSION = 656;
+  SESSION_USER = 657;
+  SET = 658;
+  SETS = 659;
+  SETOF = 660;
+  SHARE = 661;
+  SHOW = 662;
+  SIMILAR = 663;
+  SIMPLE = 664;
+  SKIP = 665;
+  SMALLINT = 666;
+  SNAPSHOT = 667;
+  SOME = 668;
+  SOURCE = 669;
+  SQL_P = 670;
+  STABLE = 671;
+  STANDALONE_P = 672;
+  START = 673;
+  STATEMENT = 674;
+  STATISTICS = 675;
+  STDIN = 676;
+  STDOUT = 677;
+  STORAGE = 678;
+  STORED = 679;
+  STRICT_P = 680;
+  STRING_P = 681;
+  STRIP_P = 682;
+  SUBSCRIPTION = 683;
+  SUBSTRING = 684;
+  SUPPORT = 685;
+  SYMMETRIC = 686;
+  SYSID = 687;
+  SYSTEM_P = 688;
+  SYSTEM_USER = 689;
+  TABLE = 690;
+  TABLES = 691;
+  TABLESAMPLE = 692;
+  TABLESPACE = 693;
+  TARGET = 694;
+  TEMP = 695;
+  TEMPLATE = 696;
+  TEMPORARY = 697;
+  TEXT_P = 698;
+  THEN = 699;
+  TIES = 700;
+  TIME = 701;
+  TIMESTAMP = 702;
+  TO = 703;
+  TRAILING = 704;
+  TRANSACTION = 705;
+  TRANSFORM = 706;
+  TREAT = 707;
+  TRIGGER = 708;
+  TRIM = 709;
+  TRUE_P = 710;
+  TRUNCATE = 711;
+  TRUSTED = 712;
+  TYPE_P = 713;
+  TYPES_P = 714;
+  UESCAPE = 715;
+  UNBOUNDED = 716;
+  UNCONDITIONAL = 717;
+  UNCOMMITTED = 718;
+  UNENCRYPTED = 719;
+  UNION = 720;
+  UNIQUE = 721;
+  UNKNOWN = 722;
+  UNLISTEN = 723;
+  UNLOGGED = 724;
+  UNTIL = 725;
+  UPDATE = 726;
+  USER = 727;
+  USING = 728;
+  VACUUM = 729;
+  VALID = 730;
+  VALIDATE = 731;
+  VALIDATOR = 732;
+  VALUE_P = 733;
+  VALUES = 734;
+  VARCHAR = 735;
+  VARIADIC = 736;
+  VARYING = 737;
+  VERBOSE = 738;
+  VERSION_P = 739;
+  VIEW = 740;
+  VIEWS = 741;
+  VOLATILE = 742;
+  WHEN = 743;
+  WHERE = 744;
+  WHITESPACE_P = 745;
+  WINDOW = 746;
+  WITH = 747;
+  WITHIN = 748;
+  WITHOUT = 749;
+  WORK = 750;
+  WRAPPER = 751;
+  WRITE = 752;
+  XML_P = 753;
+  XMLATTRIBUTES = 754;
+  XMLCONCAT = 755;
+  XMLELEMENT = 756;
+  XMLEXISTS = 757;
+  XMLFOREST = 758;
+  XMLNAMESPACES = 759;
+  XMLPARSE = 760;
+  XMLPI = 761;
+  XMLROOT = 762;
+  XMLSERIALIZE = 763;
+  XMLTABLE = 764;
+  YEAR_P = 765;
+  YES_P = 766;
+  ZONE = 767;
+  FORMAT_LA = 768;
+  NOT_LA = 769;
+  NULLS_LA = 770;
+  WITH_LA = 771;
+  WITHOUT_LA = 772;
+  MODE_TYPE_NAME = 773;
+  MODE_PLPGSQL_EXPR = 774;
+  MODE_PLPGSQL_ASSIGN1 = 775;
+  MODE_PLPGSQL_ASSIGN2 = 776;
+  MODE_PLPGSQL_ASSIGN3 = 777;
+  UMINUS = 778;
+}
diff --git a/crates/pgt_query_macros/src/iter_mut.rs b/crates/pgt_query_macros/src/iter_mut.rs
new file mode 100644
index 000000000..b0bc10dea
--- /dev/null
+++ b/crates/pgt_query_macros/src/iter_mut.rs
@@ -0,0 +1,142 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+
+use crate::proto_analyser::{FieldType, Node, ProtoAnalyzer};
+
+pub fn iter_mut_mod(analyser: ProtoAnalyzer) -> proc_macro2::TokenStream {
+    let enum_variants = analyser.enum_variants();
+    let nodes = analyser.nodes();
+
+    let mut node_variant_names = Vec::new();
+    let mut node_property_handlers = Vec::new();
+
+    // Create a map from type name to enum variant name
+    let mut type_to_variant: std::collections::HashMap<String, String> =
+        std::collections::HashMap::new();
+    for variant in &enum_variants {
+        type_to_variant.insert(variant.type_name.clone(), variant.name.clone());
+    }
+
+    for node in &nodes {
+        // Use the enum variant name from the Node enum
+        if let Some(variant_name) = type_to_variant.get(&node.name) {
+            let variant_ident = format_ident!("{}", variant_name);
+            node_variant_names.push(variant_ident);
+
+            let property_handlers = property_handlers(node);
+            node_property_handlers.push(property_handlers);
+        }
+    }
+
+    quote! {
+        use std::collections::VecDeque;
+
+        /// An iterator that provides mutable access to all nodes in an AST tree.
+        ///
+        /// This iterator performs a depth-first traversal of the AST, yielding mutable
+        /// references to each node. It uses unsafe operations internally to work with
+        /// raw pointers in the AST structure.
+        ///
+        /// # Safety Requirements
+        ///
+        /// Users of this iterator must ensure:
+        ///
+        /// - The root `NodeMut` passed to `new()` must point to a valid, properly
+        ///   constructed AST that remains alive for the iterator's lifetime
+        /// - No other code concurrently accesses or modifies the AST while this
+        ///   iterator is in use (exclusive access required)
+        /// - The AST structure must not be modified through other means while
+        ///   iterating (e.g., don't modify parent nodes while iterating children)
+        ///
+        /// # Panics
+        ///
+        /// This iterator may panic or cause undefined behavior if the safety
+        /// requirements above are violated.
+        /// ```
+        pub struct NodeMutIterator {
+            stack: VecDeque<NodeMut>,
+        }
+
+        impl NodeMutIterator {
+            /// Creates a new iterator starting from the given root node.
+            ///
+            /// # Safety
+            ///
+            /// The caller must ensure that `roots` points to valid AST nodes
+            /// and that the safety requirements documented on `NodeMutIterator`
+            /// are met throughout the iterator's lifetime.
+            pub fn new(root: NodeMut) -> Self {
+                Self {
+                    stack: VecDeque::from([root]),
+                }
+            }
+        }
+
+        impl Iterator for NodeMutIterator {
+            type Item = NodeMut;
+
+            fn next(&mut self) -> Option<Self::Item> {
+                if self.stack.is_empty() {
+                    return None;
+                }
+
+                let node = self.stack.pop_front().unwrap();
+
+                unsafe {
+                    match node {
+                        #(NodeMut::#node_variant_names(n) => {#node_property_handlers}),*,
+                        _ => {
+                            // Some node types don't have any child nodes to traverse
+                        }
+                    };
+                }
+
+                Some(node)
+            }
+        }
+    }
+}
+
+fn property_handlers(node: &Node) -> TokenStream {
+    let handlers: Vec<TokenStream> = node
+        .fields
+        .iter()
+        .filter_map(|field| {
+            let field_name = format_ident!("{}", field.name.as_str());
+            if matches!(field.r#type, FieldType::Node(_)) && field.repeated {
+                Some(quote! {
+                    n.#field_name
+                        .iter_mut()
+                        .for_each(|x| {
+                            if let Some(n) = x.node.as_mut() {
+                                self.stack.push_back(n.to_mut());
+                            }
+                        });
+                })
+            } else if matches!(field.r#type, FieldType::Node(_)) && !field.is_one_of {
+                if field.r#type == FieldType::Node(None) {
+                    Some(quote! {
+                        if let Some(n) = n.#field_name.as_mut() {
+                            if let Some(n) = n.node.as_mut() {
+                                self.stack.push_back(n.to_mut());
+                            }
+                        }
+                    })
+                } else {
+                    Some(quote! {
+                        if let Some(field_node) = n.#field_name.as_mut() {
+                            self.stack.push_back(field_node.to_mut());
+                        }
+                    })
+                }
+            } else {
+                None // Filter out non-node fields
+            }
+        })
+        .collect();
+
+    quote! {
+        let n = n.as_mut().unwrap();
+        #(#handlers)*
+    }
+}
diff --git a/crates/pgt_query_macros/src/iter_ref.rs b/crates/pgt_query_macros/src/iter_ref.rs
new file mode 100644
index 000000000..8e232340f
--- /dev/null
+++ b/crates/pgt_query_macros/src/iter_ref.rs
@@ -0,0 +1,105 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+
+use crate::proto_analyser::{FieldType, Node, ProtoAnalyzer};
+
+pub fn iter_ref_mod(analyser: ProtoAnalyzer) -> proc_macro2::TokenStream {
+    let enum_variants = analyser.enum_variants();
+    let nodes = analyser.nodes();
+
+    let mut node_variant_names = Vec::new();
+    let mut node_property_handlers = Vec::new();
+
+    let mut type_to_variant: std::collections::HashMap<String, String> =
+        std::collections::HashMap::new();
+    for variant in &enum_variants {
+        type_to_variant.insert(variant.type_name.clone(), variant.name.clone());
+    }
+
+    for node in &nodes {
+        if let Some(variant_name) = type_to_variant.get(&node.name) {
+            let variant_ident = format_ident!("{}", variant_name);
+            node_variant_names.push(variant_ident);
+
+            let property_handlers = property_handlers(node);
+            node_property_handlers.push(quote! {
+                #(#property_handlers)*
+            });
+        }
+    }
+
+    quote! {
+        use std::collections::VecDeque;
+
+        pub struct NodeRefIterator<'a>{
+            stack: VecDeque<NodeRef<'a>>,
+        }
+
+        impl<'a> NodeRefIterator<'a> {
+            pub fn new(root: NodeRef<'a>) -> Self {
+                Self {
+                    stack: VecDeque::from([root]),
+                }
+            }
+        }
+
+        impl<'a> Iterator for NodeRefIterator<'a> {
+            type Item = NodeRef<'a>;
+
+            fn next(&mut self) -> Option<Self::Item> {
+                if self.stack.is_empty() {
+                    return None;
+                }
+
+                let node = self.stack.pop_front().unwrap();
+
+                match &node {
+                    #(NodeRef::#node_variant_names(n) => {#node_property_handlers}),*,
+                    _ => {
+                        // Some node types don't have any child nodes to traverse
+                    }
+                };
+
+                Some(node)
+            }
+        }
+    }
+}
+
+fn property_handlers(node: &Node) -> Vec<TokenStream> {
+    node.fields
+        .iter()
+        .filter_map(|field| {
+            let field_name = format_ident!("{}", field.name.as_str());
+            if matches!(field.r#type, FieldType::Node(_)) && field.repeated {
+                Some(quote! {
+                    n.#field_name
+                        .iter()
+                        .for_each(|x| {
+                            if let Some(n) = x.node.as_ref() {
+                                self.stack.push_back(n.to_ref());
+                            }
+                        });
+                })
+            } else if matches!(field.r#type, FieldType::Node(_)) && !field.is_one_of {
+                if field.r#type == FieldType::Node(None) {
+                    Some(quote! {
+                        if let Some(n) = &n.#field_name {
+                            if let Some(n) = n.node.as_ref() {
+                                self.stack.push_back(n.to_ref());
+                            }
+                        }
+                    })
+                } else {
+                    Some(quote! {
+                        if let Some(field_node) = &n.#field_name {
+                            self.stack.push_back(field_node.to_ref());
+                        }
+                    })
+                }
+            } else {
+                None // Filter out non-node fields
+            }
+        })
+        .collect()
+}
diff --git a/crates/pgt_query_macros/src/lib.rs b/crates/pgt_query_macros/src/lib.rs
new file mode 100644
index 000000000..718da161e
--- /dev/null
+++ b/crates/pgt_query_macros/src/lib.rs
@@ -0,0 +1,106 @@
+use iter_mut::iter_mut_mod;
+use iter_ref::iter_ref_mod;
+use node_enum::node_enum_mod;
+use node_mut::node_mut_mod;
+use node_ref::node_ref_mod;
+use node_structs::node_structs_mod;
+use proto_analyser::ProtoAnalyzer;
+use quote::quote;
+use std::path;
+
+mod iter_mut;
+mod iter_ref;
+mod node_enum;
+mod node_mut;
+mod node_ref;
+mod node_structs;
+mod proto_analyser;
+
+#[proc_macro]
+pub fn node_ref_codegen(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let analyser = ProtoAnalyzer::from(&proto_file_path()).unwrap();
+
+    let node_ref = node_ref_mod(analyser);
+
+    quote! {
+        use crate::*;
+
+        #node_ref
+    }
+    .into()
+}
+
+#[proc_macro]
+pub fn node_mut_codegen(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let analyser = ProtoAnalyzer::from(&proto_file_path()).unwrap();
+
+    let node_mut = node_mut_mod(analyser);
+
+    quote! {
+        use crate::*;
+
+        #node_mut
+    }
+    .into()
+}
+
+#[proc_macro]
+pub fn node_structs_codegen(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let analyser = ProtoAnalyzer::from(&proto_file_path()).unwrap();
+
+    let conversions = node_structs_mod(analyser);
+
+    quote! {
+        use crate::*;
+
+        #conversions
+    }
+    .into()
+}
+
+#[proc_macro]
+pub fn node_enum_codegen(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let analyser = ProtoAnalyzer::from(&proto_file_path()).unwrap();
+
+    let node_enum = node_enum_mod(analyser);
+
+    quote! {
+        use crate::*;
+
+        #node_enum
+    }
+    .into()
+}
+
+#[proc_macro]
+pub fn iter_ref_codegen(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let analyser = ProtoAnalyzer::from(&proto_file_path()).unwrap();
+
+    let iterator = iter_ref_mod(analyser);
+
+    quote! {
+        use crate::*;
+
+        #iterator
+    }
+    .into()
+}
+
+#[proc_macro]
+pub fn iter_mut_codegen(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let analyser = ProtoAnalyzer::from(&proto_file_path()).unwrap();
+
+    let iterator = iter_mut_mod(analyser);
+
+    quote! {
+        use crate::*;
+
+        #iterator
+    }
+    .into()
+}
+
+fn proto_file_path() -> path::PathBuf {
+    // Use the path set by the build script
+    path::PathBuf::from(env!("PG_QUERY_PROTO_PATH"))
+}
diff --git a/crates/pgt_query_macros/src/node_enum.rs b/crates/pgt_query_macros/src/node_enum.rs
new file mode 100644
index 000000000..0801bbab6
--- /dev/null
+++ b/crates/pgt_query_macros/src/node_enum.rs
@@ -0,0 +1,44 @@
+use quote::{format_ident, quote};
+
+use crate::proto_analyser::ProtoAnalyzer;
+
+pub fn node_enum_mod(analyser: ProtoAnalyzer) -> proc_macro2::TokenStream {
+    let node_variants = analyser.enum_variants();
+
+    let mut to_ref_matches = Vec::new();
+    let mut to_mut_matches = Vec::new();
+
+    for variant in &node_variants {
+        let variant_ident = format_ident!("{}", &variant.name);
+
+        to_ref_matches.push(quote! {
+            NodeEnum::#variant_ident(n) => NodeRef::#variant_ident(&n)
+        });
+
+        if variant.boxed {
+            to_mut_matches.push(quote! {
+                NodeEnum::#variant_ident(n) => NodeMut::#variant_ident(&mut **n as *mut _)
+            });
+        } else {
+            to_mut_matches.push(quote! {
+                NodeEnum::#variant_ident(n) => NodeMut::#variant_ident(n as *mut _)
+            });
+        }
+    }
+
+    quote! {
+        impl NodeEnum {
+            pub fn to_ref(&self) -> NodeRef {
+                match self {
+                    #(#to_ref_matches,)*
+                }
+            }
+
+            pub fn to_mut(&mut self) -> NodeMut {
+                match self {
+                    #(#to_mut_matches,)*
+                }
+            }
+        }
+    }
+}
diff --git a/crates/pgt_query_macros/src/node_mut.rs b/crates/pgt_query_macros/src/node_mut.rs
new file mode 100644
index 000000000..52120c1a9
--- /dev/null
+++ b/crates/pgt_query_macros/src/node_mut.rs
@@ -0,0 +1,50 @@
+use quote::{format_ident, quote};
+
+use crate::proto_analyser::ProtoAnalyzer;
+
+pub fn node_mut_mod(analyser: ProtoAnalyzer) -> proc_macro2::TokenStream {
+    let node_variants = analyser.enum_variants();
+
+    let mut to_enum_matches = Vec::new();
+    let mut node_enum_variants = Vec::new();
+
+    for variant in &node_variants {
+        let variant_ident = format_ident!("{}", &variant.name);
+        let type_ident = format_ident!("{}", &variant.type_name);
+
+        if variant.boxed {
+            // For boxed variants, we need to box the cloned value
+            to_enum_matches.push(quote! {
+                NodeMut::#variant_ident(n) => Ok(NodeEnum::#variant_ident(Box::new(n.as_ref().ok_or(err)?.clone())))
+            });
+        } else {
+            // For non-boxed variants, clone directly
+            to_enum_matches.push(quote! {
+                NodeMut::#variant_ident(n) => Ok(NodeEnum::#variant_ident(n.as_ref().ok_or(err)?.clone()))
+            });
+        }
+
+        node_enum_variants.push(quote! {
+            #variant_ident(*mut protobuf::#type_ident)
+        });
+    }
+
+    quote! {
+        #[derive(Debug, Copy, Clone)]
+        pub enum NodeMut {
+            #(#node_enum_variants, )*
+        }
+
+        impl NodeMut {
+            pub fn to_enum(self) -> Result<NodeEnum> {
+                unsafe {
+                    let err = Error::InvalidPointer;
+                    match self {
+                        #(#to_enum_matches,)*
+                        _ => Err(Error::InvalidPointer),
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/crates/pgt_query_macros/src/node_ref.rs b/crates/pgt_query_macros/src/node_ref.rs
new file mode 100644
index 000000000..64f9b7c49
--- /dev/null
+++ b/crates/pgt_query_macros/src/node_ref.rs
@@ -0,0 +1,46 @@
+use quote::{format_ident, quote};
+
+use crate::proto_analyser::ProtoAnalyzer;
+
+pub fn node_ref_mod(analyser: ProtoAnalyzer) -> proc_macro2::TokenStream {
+    let node_variants = analyser.enum_variants();
+
+    let mut to_enum_matches = Vec::new();
+    let mut node_enum_variants = Vec::new();
+
+    for variant in &node_variants {
+        let variant_ident = format_ident!("{}", &variant.name);
+        let type_ident = format_ident!("{}", &variant.type_name);
+
+        if variant.boxed {
+            // For boxed variants, we need to box the cloned value
+            to_enum_matches.push(quote! {
+                NodeRef::#variant_ident(n) => NodeEnum::#variant_ident(::prost::alloc::boxed::Box::new((*n).clone()))
+            });
+        } else {
+            // For non-boxed variants, clone directly
+            to_enum_matches.push(quote! {
+                NodeRef::#variant_ident(n) => NodeEnum::#variant_ident((*n).clone())
+            });
+        }
+
+        node_enum_variants.push(quote! {
+            #variant_ident(&'a protobuf::#type_ident)
+        });
+    }
+
+    quote! {
+        #[derive(Debug, Copy, Clone)]
+        pub enum NodeRef<'a> {
+            #(#node_enum_variants,)*
+        }
+
+        impl<'a> NodeRef<'a> {
+            pub fn to_enum(self) -> NodeEnum {
+                match self {
+                    #(#to_enum_matches,)*
+                }
+            }
+        }
+    }
+}
diff --git a/crates/pgt_query_macros/src/node_structs.rs b/crates/pgt_query_macros/src/node_structs.rs
new file mode 100644
index 000000000..52fca2e00
--- /dev/null
+++ b/crates/pgt_query_macros/src/node_structs.rs
@@ -0,0 +1,30 @@
+use quote::{format_ident, quote};
+
+use crate::proto_analyser::ProtoAnalyzer;
+
+pub fn node_structs_mod(analyser: ProtoAnalyzer) -> proc_macro2::TokenStream {
+    let node_variants = analyser.enum_variants();
+
+    let mut impls = Vec::new();
+
+    for variant in &node_variants {
+        let node_ident = format_ident!("{}", &variant.name);
+        let type_ident = format_ident!("{}", &variant.type_name);
+
+        impls.push(quote! {
+            impl protobuf::#type_ident {
+                pub fn to_ref(&self) -> NodeRef {
+                    NodeRef::#node_ident(self)
+                }
+
+                pub fn to_mut(&mut self) -> NodeMut {
+                    NodeMut::#node_ident(self)
+                }
+            }
+        });
+    }
+
+    quote! {
+        #(#impls)*
+    }
+}
diff --git a/crates/pgt_query_macros/src/proto_analyser.rs b/crates/pgt_query_macros/src/proto_analyser.rs
new file mode 100644
index 000000000..26a18b600
--- /dev/null
+++ b/crates/pgt_query_macros/src/proto_analyser.rs
@@ -0,0 +1,252 @@
+use std::{
+    collections::{HashMap, HashSet},
+    path::Path,
+};
+
+use convert_case::{Case, Casing};
+use prost_reflect::{
+    DescriptorError, DescriptorPool, FieldDescriptor, MessageDescriptor,
+    prost_types::{
+        FieldDescriptorProto,
+        field_descriptor_proto::{Label, Type},
+    },
+};
+
+pub(crate) struct ProtoAnalyzer {
+    pool: DescriptorPool,
+    message_graph: HashMap<String, Vec<String>>,
+}
+
+pub(crate) struct EnumVariant {
+    pub name: String,
+    pub type_name: String,
+    pub boxed: bool,
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) enum FieldType {
+    Node(Option<String>),
+    Enum(String),
+    Literal,
+}
+
+pub(crate) struct Field {
+    pub name: String,
+    pub r#type: FieldType,
+    pub repeated: bool,
+    pub is_one_of: bool,
+}
+
+pub(crate) struct Node {
+    pub name: String,
+    #[allow(dead_code)]
+    pub enum_variant_name: String,
+    pub fields: Vec<Field>,
+}
+
+impl ProtoAnalyzer {
+    pub fn from(proto_file: &Path) -> Result<Self, DescriptorError> {
+        let include_path = proto_file
+            .parent()
+            .expect("Proto file must have a parent directory");
+
+        // protox::compile expects the proto file to be relative to the include path
+        let file_name = proto_file
+            .file_name()
+            .expect("Proto file must have a file name");
+
+        let pool = DescriptorPool::from_file_descriptor_set(
+            protox::compile([file_name], [include_path]).expect("unable to parse"),
+        )?;
+
+        let mut analyzer = ProtoAnalyzer {
+            pool,
+            message_graph: HashMap::new(),
+        };
+
+        // Build the message graph
+        analyzer.build_message_graph();
+
+        Ok(analyzer)
+    }
+
+    pub fn nodes(&self) -> Vec<Node> {
+        let mut nodes = Vec::new();
+
+        for msg in self.pool.all_messages() {
+            if ["ParseResult", "ScanResult", "Node", "ScanToken"].contains(&msg.name()) {
+                continue;
+            }
+            let fields = msg
+                .fields()
+                .map(|f| {
+                    let field_type = match f.field_descriptor_proto().r#type() {
+                        Type::Message => match f.field_descriptor_proto().type_name() {
+                            ".pg_query.Node" => FieldType::Node(None),
+                            name => {
+                                FieldType::Node(Some(name.to_string().replace(".pg_query.", "")))
+                            }
+                        },
+                        Type::Enum => FieldType::Enum(
+                            f.field_descriptor_proto()
+                                .type_name()
+                                .to_string()
+                                .replace(".pg_query.", ""),
+                        ),
+                        _ => FieldType::Literal,
+                    };
+
+                    Field {
+                        name: f.name().to_string(),
+                        r#type: field_type,
+                        repeated: f.is_list(),
+                        is_one_of: f.containing_oneof().is_some(),
+                    }
+                })
+                .collect();
+
+            nodes.push(Node {
+                name: msg.name().to_string(),
+                enum_variant_name: msg.name().to_case(Case::Pascal), // Convert to PascalCase for enum variant name
+                fields,
+            });
+        }
+
+        nodes
+    }
+
+    pub fn enum_variants(&self) -> Vec<EnumVariant> {
+        let node = self
+            .pool
+            .get_message_by_name(".pg_query.Node")
+            .expect("Node message not found");
+
+        let mut variants = Vec::new();
+        for field in node.fields() {
+            // The prost-generated variant name is derived from the field name using snake_case to PascalCase conversion
+            // For example: ctesearch_clause -> CtesearchClause
+            let field_name = field.name();
+            let variant_name = field_name.to_case(Case::Pascal);
+
+            // Get the actual proto type name (the message type)
+            let proto_type_name = field
+                .field_descriptor_proto()
+                .type_name()
+                .split('.')
+                .next_back()
+                .unwrap_or(&variant_name);
+
+            // The Rust type name is the proto type name converted to PascalCase
+            // For example: CTESearchClause -> CteSearchClause
+            let type_name = proto_type_name.to_case(Case::Pascal);
+
+            let boxed = self.is_field_boxed(&field, &node);
+
+            variants.push(EnumVariant {
+                name: variant_name,
+                type_name,
+                boxed,
+            });
+        }
+
+        variants
+    }
+
+    /// Build a graph of message dependencies for cycle detection
+    fn build_message_graph(&mut self) {
+        // Collect all messages first to avoid borrowing issues
+        let mut all_messages = Vec::new();
+        for file in self.pool.files() {
+            for message in file.messages() {
+                all_messages.push(message);
+            }
+        }
+
+        // Now add them to the graph
+        for message in all_messages {
+            self.add_message_to_graph(&message);
+        }
+    }
+
+    /// Add a message and its dependencies to the graph
+    fn add_message_to_graph(&mut self, message: &MessageDescriptor) {
+        let msg_fq_name = format!(".{}", message.full_name());
+        let mut dependencies = Vec::new();
+
+        // Check all fields for message type dependencies
+        for field in message.fields() {
+            if let Some(field_message) = field.kind().as_message() {
+                // Only add non-repeated message fields as dependencies
+                // since repeated fields are already heap allocated in Vec
+                if !field.is_list() {
+                    let field_fq_name = format!(".{}", field_message.full_name());
+                    dependencies.push(field_fq_name);
+                }
+            }
+        }
+
+        self.message_graph.insert(msg_fq_name, dependencies);
+
+        // Recursively add nested messages
+        for nested in message.child_messages() {
+            self.add_message_to_graph(&nested);
+        }
+    }
+
+    /// Detect if a field will be boxed by prost due to recursive nesting
+    fn is_field_boxed(&self, field: &FieldDescriptor, parent_message: &MessageDescriptor) -> bool {
+        // Check if this is a message field that should be boxed
+        let parent_fq_name = format!(".{}", parent_message.full_name());
+        self.is_boxed(&parent_fq_name, field.field_descriptor_proto())
+    }
+
+    /// Check if there's a path from parent_message to field_type in the message graph
+    /// This indicates that field_type is transitively contained within parent_message
+    fn is_nested(&self, parent_message_name: &str, field_type_name: &str) -> bool {
+        self.has_path(parent_message_name, field_type_name, &mut HashSet::new())
+    }
+
+    /// Recursive helper to find if there's a path from 'from' to 'to' in the message graph
+    fn has_path(&self, from: &str, to: &str, visited: &mut HashSet<String>) -> bool {
+        // If we've already visited this node, return false to avoid cycles
+        if visited.contains(from) {
+            return false;
+        }
+
+        // If we've reached the target, we found a path
+        if from == to {
+            return true;
+        }
+
+        visited.insert(from.to_string());
+
+        // Check all dependencies of the current message
+        if let Some(dependencies) = self.message_graph.get(from) {
+            for dep in dependencies {
+                if self.has_path(dep, to, visited) {
+                    return true;
+                }
+            }
+        }
+
+        false
+    }
+
+    /// Returns whether the Rust type for this message field is `Box<_>`.
+    fn is_boxed(&self, fq_message_name: &str, field: &FieldDescriptorProto) -> bool {
+        if field.label() == Label::Repeated {
+            // Repeated field are stored in Vec, therefore it is already heap allocated
+            return false;
+        }
+        let fd_type = field.r#type();
+        if fd_type == Type::Message || fd_type == Type::Group {
+            // The field should be boxed if the field type transitively contains the parent message
+            // This prevents infinitely sized type definitions
+            if let Some(field_type_name) = field.type_name.as_ref() {
+                // IMPORTANT: Check if field_type_name contains fq_message_name (not the other way around)
+                return self.is_nested(field_type_name, fq_message_name);
+            }
+        }
+        false
+    }
+}
diff --git a/crates/pgt_query_proto_parser/src/lib.rs b/crates/pgt_query_proto_parser/src/lib.rs
deleted file mode 100644
index 12f8cf9cd..000000000
--- a/crates/pgt_query_proto_parser/src/lib.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//! A parser for the libg_query proto file
-//!
-//! This crate provides a parser for the libg_query proto file, and a struct to represent and interact with the parsed file.
-
-mod proto_file;
-mod proto_parser;
-
-pub use crate::proto_file::{Field, FieldType, Node, ProtoFile, Token};
-pub use crate::proto_parser::ProtoParser;
diff --git a/crates/pgt_query_proto_parser/src/proto_file.rs b/crates/pgt_query_proto_parser/src/proto_file.rs
deleted file mode 100644
index 2cc327984..000000000
--- a/crates/pgt_query_proto_parser/src/proto_file.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-/// The FieldTypes of a protobuf message
-#[derive(Debug, Eq, PartialEq)]
-pub enum FieldType {
-    Node,
-    Double,
-    Float,
-    Int64,
-    Uint64,
-    Int32,
-    Fixed64,
-    Fixed32,
-    Bool,
-    String,
-    Group,
-    Message,
-    Bytes,
-    Uint32,
-    Enum,
-    Sfixed32,
-    Sfixed64,
-    Sint32,
-    Sint64,
-}
-
-/// A libg_query token
-#[derive(Debug)]
-pub struct Token {
-    pub name: String,
-    pub value: i32,
-}
-
-/// A libg_query field
-#[derive(Debug)]
-pub struct Field {
-    pub name: String,
-    pub node_name: Option<String>,
-    pub enum_variant_name: Option<String>,
-    pub field_type: FieldType,
-    pub repeated: bool,
-    pub is_one_of: bool,
-}
-
-/// A libg_query node
-#[derive(Debug)]
-pub struct Node {
-    pub name: String,
-    pub fields: Vec<Field>,
-}
-
-/// The libg_query proto file
-pub struct ProtoFile {
-    pub tokens: Vec<Token>,
-    pub nodes: Vec<Node>,
-}
-
-impl ProtoFile {
-    pub fn node(&self, name: &str) -> Option<&Node> {
-        self.nodes.iter().find(|n| n.name == name)
-    }
-}
diff --git a/crates/pgt_query_proto_parser/src/proto_parser.rs b/crates/pgt_query_proto_parser/src/proto_parser.rs
deleted file mode 100644
index 56f93c6e8..000000000
--- a/crates/pgt_query_proto_parser/src/proto_parser.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-use convert_case::{Case, Casing};
-use protobuf::descriptor::{FileDescriptorProto, field_descriptor_proto::Label};
-use protobuf_parse::Parser;
-use std::{ffi::OsStr, path::Path};
-
-use crate::proto_file::{Field, FieldType, Node, ProtoFile, Token};
-
-/// The parser for the libg_query proto file
-pub struct ProtoParser {
-    inner: FileDescriptorProto,
-}
-
-impl ProtoParser {
-    pub fn new(file_path: &impl AsRef<OsStr>) -> Self {
-        let proto_file = Path::new(file_path);
-        let proto_dir = proto_file.parent().unwrap();
-
-        let result = Parser::new()
-            .pure()
-            .include(proto_dir)
-            .input(proto_file)
-            .parse_and_typecheck()
-            .unwrap();
-
-        ProtoParser {
-            inner: result.file_descriptors[0].clone(),
-        }
-    }
-
-    pub fn parse(&self) -> ProtoFile {
-        ProtoFile {
-            tokens: self.tokens(),
-            nodes: self.nodes(),
-        }
-    }
-
-    fn tokens(&self) -> Vec<Token> {
-        self.inner
-            .enum_type
-            .iter()
-            .find(|e| e.name == Some("Token".into()))
-            .unwrap()
-            .value
-            .iter()
-            .map(|e| Token {
-                // token names in proto are UPPERCASE_SNAKE_CASE
-                name: e.name.clone().unwrap().to_case(Case::UpperCamel),
-                value: e.number.unwrap(),
-            })
-            .collect()
-    }
-
-    fn get_enum_variant_name(&self, type_name: &str) -> Option<String> {
-        let variant = self
-            .inner
-            .message_type
-            .iter()
-            .find(|e| e.name == Some("Node".into()))
-            .unwrap()
-            .field
-            .iter()
-            .find(|e| e.type_name().split(".").last().unwrap() == type_name);
-        variant.map(|v| v.name.clone().unwrap().to_case(Case::UpperCamel))
-    }
-
-    fn nodes(&self) -> Vec<Node> {
-        self.inner
-            .message_type
-            .iter()
-            .find(|e| e.name == Some("Node".into()))
-            .unwrap()
-            .field
-            .iter()
-            .map(|e| {
-                let name: String = e.name.to_owned().unwrap().to_case(Case::UpperCamel);
-                let node = self
-                    .inner
-                    .message_type
-                    .iter()
-                    .find(|n| {
-                        n.name.clone().unwrap().to_case(Case::UpperCamel)
-                            == e.json_name.as_ref().unwrap().to_case(Case::UpperCamel)
-                    })
-                    .unwrap();
-
-                let mut fields: Vec<Field> = Vec::new();
-                // from node fields
-                fields.append(&mut
-                        node
-                        .field
-                        .iter()
-                        .filter_map(|e| {
-                            // skip one of fields, they are handled separately
-                            if e.has_oneof_index() {
-                                return None;
-                            }
-                            // use label and type to get the field type
-                            let type_name: FieldType = match e.type_name() {
-                                "" => match e.type_() {
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_DOUBLE => FieldType::Double,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_FLOAT => FieldType::Float,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_INT64 => FieldType::Int64,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_UINT64 => FieldType::Uint64,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_INT32 => FieldType::Int32,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_FIXED64 => FieldType::Fixed64,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_FIXED32 => FieldType::Fixed32,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_BOOL => FieldType::Bool,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_STRING => FieldType::String,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_GROUP => FieldType::Group,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_MESSAGE => FieldType::Message,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_BYTES => FieldType::Bytes,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_UINT32 => FieldType::Uint32,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_ENUM => FieldType::Enum,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_SFIXED32 => FieldType::Sfixed32,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_SFIXED64 => FieldType::Sfixed64,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_SINT32 => FieldType::Sint32,
-                                    protobuf::descriptor::field_descriptor_proto::Type::TYPE_SINT64 => FieldType::Sint64,
-                                },
-                                _ => {
-                                    if !e.type_name().starts_with(".pg_query") {
-                                        panic!("Unknown type: {}", e.type_name());
-
-                                    }
-                                    if e.type_() == protobuf::descriptor::field_descriptor_proto::Type::TYPE_ENUM {
-                                        FieldType::Enum
-                                    } else {
-                                        FieldType::Node
-                                    }
-                                },
-                            };
-                            let mut node_name = None;
-                            let mut enum_variant_name = None;
-                            if e.type_name().starts_with(".pg_query") {
-                                let n = e.type_name().split(".").last().unwrap().to_string();
-                                node_name = Some(n.clone());
-                                if n != "Node" {
-                                    enum_variant_name = self.get_enum_variant_name(e.type_name().split(".").last().unwrap().to_string().as_str());
-                                }
-                            }
-                            // TODO: node name must be derived from the property name in the node
-                            // enum
-                            Some(Field {
-                                name: e.name.clone().unwrap(),
-                                node_name,
-                                enum_variant_name,
-                                field_type: type_name,
-                                repeated: e.label() == Label::LABEL_REPEATED,
-                                is_one_of: false,
-                            })
-                        })
-                        .collect()
-                    );
-
-                    // one of declarations
-                    fields.append(&mut
-                        node
-                        .oneof_decl
-                        .iter()
-                        .map(|e| {
-                            Field {
-                       name: e.name.clone().unwrap(),
-                       node_name: Some("Node".to_string()),
-                       enum_variant_name: None,
-                       field_type: FieldType::Node,
-                       repeated: false,
-                       is_one_of: true,
-                   }
-                        })
-                        .collect()
-                              );
-                Node {
-                    // token names in proto are UPPERCASE_SNAKE_CASE
-                    name: name.clone(),
-                    fields,
-                }
-            })
-            .collect()
-    }
-}
diff --git a/crates/pgt_schema_cache/src/extensions.rs b/crates/pgt_schema_cache/src/extensions.rs
new file mode 100644
index 000000000..8494397cd
--- /dev/null
+++ b/crates/pgt_schema_cache/src/extensions.rs
@@ -0,0 +1,22 @@
+use sqlx::PgPool;
+
+use crate::schema_cache::SchemaCacheItem;
+
+#[derive(Debug, Default)]
+pub struct Extension {
+    pub name: String,
+    pub schema: Option<String>,
+    pub default_version: String,
+    pub installed_version: Option<String>,
+    pub comment: Option<String>,
+}
+
+impl SchemaCacheItem for Extension {
+    type Item = Extension;
+
+    async fn load(pool: &PgPool) -> Result<Vec<Extension>, sqlx::Error> {
+        sqlx::query_file_as!(Extension, "src/queries/extensions.sql")
+            .fetch_all(pool)
+            .await
+    }
+}
diff --git a/crates/pgt_schema_cache/src/lib.rs b/crates/pgt_schema_cache/src/lib.rs
index b67f94127..6440cd01a 100644
--- a/crates/pgt_schema_cache/src/lib.rs
+++ b/crates/pgt_schema_cache/src/lib.rs
@@ -3,6 +3,7 @@
 #![allow(dead_code)]
 
 mod columns;
+mod extensions;
 mod functions;
 mod policies;
 mod roles;
@@ -14,6 +15,7 @@ mod types;
 mod versions;
 
 pub use columns::*;
+pub use extensions::Extension;
 pub use functions::{Behavior, Function, FunctionArg, FunctionArgs, ProcKind};
 pub use policies::{Policy, PolicyCommand};
 pub use roles::*;
diff --git a/crates/pgt_schema_cache/src/queries/extensions.sql b/crates/pgt_schema_cache/src/queries/extensions.sql
new file mode 100644
index 000000000..aedc71b21
--- /dev/null
+++ b/crates/pgt_schema_cache/src/queries/extensions.sql
@@ -0,0 +1,10 @@
+SELECT
+  e.name as "name!",
+  n.nspname AS schema,
+  e.default_version as "default_version!",
+  x.extversion AS installed_version,
+  e.comment
+FROM
+  pg_available_extensions() e(name, default_version, comment)
+  LEFT JOIN pg_extension x ON e.name = x.extname
+  LEFT JOIN pg_namespace n ON x.extnamespace = n.oid
diff --git a/crates/pgt_schema_cache/src/queries/triggers.sql b/crates/pgt_schema_cache/src/queries/triggers.sql
index c28cc39fa..895d1be0d 100644
--- a/crates/pgt_schema_cache/src/queries/triggers.sql
+++ b/crates/pgt_schema_cache/src/queries/triggers.sql
@@ -1,17 +1,18 @@
--- we need to join tables from the pg_catalog since "TRUNCATE" triggers are 
+-- we need to join tables from the pg_catalog since "TRUNCATE" triggers are
 -- not available in the information_schema.trigger table.
-select 
-  t.tgname as "name!",
-  c.relname as "table_name!",
-  p.proname as "proc_name!",
-  n.nspname as "schema_name!",
-  t.tgtype as "details_bitmask!"
-from 
-  pg_catalog.pg_trigger t 
-  left join pg_catalog.pg_proc p on t.tgfoid = p.oid
-  left join pg_catalog.pg_class c on t.tgrelid = c.oid
-  left join pg_catalog.pg_namespace n on c.relnamespace = n.oid
-where 
-  -- triggers enforcing constraints (e.g. unique fields) should not be included.
-  t.tgisinternal = false and 
-  t.tgconstraint = 0;
+select
+ t.tgname as "name!",
+ c.relname as "table_name!",
+ p.proname as "proc_name!",
+ proc_ns.nspname as "proc_schema!",
+ table_ns.nspname as "table_schema!",
+ t.tgtype as "details_bitmask!"
+from
+ pg_catalog.pg_trigger t
+left join pg_catalog.pg_proc p on t.tgfoid = p.oid
+left join pg_catalog.pg_class c on t.tgrelid = c.oid
+left join pg_catalog.pg_namespace table_ns on c.relnamespace = table_ns.oid
+left join pg_catalog.pg_namespace proc_ns on p.pronamespace = proc_ns.oid
+where
+ t.tgisinternal = false and
+ t.tgconstraint = 0;
diff --git a/crates/pgt_schema_cache/src/schema_cache.rs b/crates/pgt_schema_cache/src/schema_cache.rs
index 8fb9683b1..84bcd77c8 100644
--- a/crates/pgt_schema_cache/src/schema_cache.rs
+++ b/crates/pgt_schema_cache/src/schema_cache.rs
@@ -7,7 +7,7 @@ use crate::schemas::Schema;
 use crate::tables::Table;
 use crate::types::PostgresType;
 use crate::versions::Version;
-use crate::{Role, Trigger};
+use crate::{Extension, Role, Trigger};
 
 #[derive(Debug, Default)]
 pub struct SchemaCache {
@@ -18,13 +18,25 @@ pub struct SchemaCache {
     pub versions: Vec<Version>,
     pub columns: Vec<Column>,
     pub policies: Vec<Policy>,
+    pub extensions: Vec<Extension>,
     pub triggers: Vec<Trigger>,
     pub roles: Vec<Role>,
 }
 
 impl SchemaCache {
     pub async fn load(pool: &PgPool) -> Result<SchemaCache, sqlx::Error> {
-        let (schemas, tables, functions, types, versions, columns, policies, triggers, roles) = futures_util::try_join!(
+        let (
+            schemas,
+            tables,
+            functions,
+            types,
+            versions,
+            columns,
+            policies,
+            triggers,
+            roles,
+            extensions,
+        ) = futures_util::try_join!(
             Schema::load(pool),
             Table::load(pool),
             Function::load(pool),
@@ -33,7 +45,8 @@ impl SchemaCache {
             Column::load(pool),
             Policy::load(pool),
             Trigger::load(pool),
-            Role::load(pool)
+            Role::load(pool),
+            Extension::load(pool),
         )?;
 
         Ok(SchemaCache {
@@ -46,17 +59,10 @@ impl SchemaCache {
             policies,
             triggers,
             roles,
+            extensions,
         })
     }
 
-    /// Applies an AST node to the repository
-    ///
-    /// For example, alter table add column will add the column to the table if it does not exist
-    /// yet
-    pub fn mutate(&mut self) {
-        unimplemented!();
-    }
-
     pub fn find_table(&self, name: &str, schema: Option<&str>) -> Option<&Table> {
         self.tables
             .iter()
diff --git a/crates/pgt_schema_cache/src/triggers.rs b/crates/pgt_schema_cache/src/triggers.rs
index 2b2a3afff..d0a4788a0 100644
--- a/crates/pgt_schema_cache/src/triggers.rs
+++ b/crates/pgt_schema_cache/src/triggers.rs
@@ -82,20 +82,22 @@ impl TryFrom<i16> for TriggerTiming {
 pub struct TriggerQueried {
     name: String,
     table_name: String,
-    schema_name: String,
+    table_schema: String,
     proc_name: String,
+    proc_schema: String,
     details_bitmask: i16,
 }
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct Trigger {
-    name: String,
-    table_name: String,
-    schema_name: String,
-    proc_name: String,
-    affected: TriggerAffected,
-    timing: TriggerTiming,
-    events: Vec<TriggerEvent>,
+    pub name: String,
+    pub table_name: String,
+    pub table_schema: String,
+    pub proc_name: String,
+    pub proc_schema: String,
+    pub affected: TriggerAffected,
+    pub timing: TriggerTiming,
+    pub events: Vec<TriggerEvent>,
 }
 
 impl From<TriggerQueried> for Trigger {
@@ -104,7 +106,8 @@ impl From<TriggerQueried> for Trigger {
             name: value.name,
             table_name: value.table_name,
             proc_name: value.proc_name,
-            schema_name: value.schema_name,
+            proc_schema: value.proc_schema,
+            table_schema: value.table_schema,
             affected: value.details_bitmask.into(),
             timing: value.details_bitmask.try_into().unwrap(),
             events: TriggerEvents::from(value.details_bitmask).0,
@@ -141,7 +144,7 @@ mod tests {
                     id serial primary key,
                     name text
                 );
-    
+
                 create or replace function public.log_user_insert()
                 returns trigger as $$
                 begin
@@ -149,17 +152,17 @@ mod tests {
                     return new;
                 end;
                 $$ language plpgsql;
-    
+
                 create trigger trg_users_insert
                     before insert on public.users
                     for each row
                     execute function public.log_user_insert();
-    
+
                 create trigger trg_users_update
                     after update or insert on public.users
                     for each statement
                     execute function public.log_user_insert();
-    
+
                 create trigger trg_users_delete
                     before delete on public.users
                     for each row
@@ -186,7 +189,7 @@ mod tests {
             .iter()
             .find(|t| t.name == "trg_users_insert")
             .unwrap();
-        assert_eq!(insert_trigger.schema_name, "public");
+        assert_eq!(insert_trigger.table_schema, "public");
         assert_eq!(insert_trigger.table_name, "users");
         assert_eq!(insert_trigger.timing, TriggerTiming::Before);
         assert_eq!(insert_trigger.affected, TriggerAffected::Row);
@@ -197,7 +200,7 @@ mod tests {
             .iter()
             .find(|t| t.name == "trg_users_update")
             .unwrap();
-        assert_eq!(insert_trigger.schema_name, "public");
+        assert_eq!(insert_trigger.table_schema, "public");
         assert_eq!(insert_trigger.table_name, "users");
         assert_eq!(update_trigger.timing, TriggerTiming::After);
         assert_eq!(update_trigger.affected, TriggerAffected::Statement);
@@ -209,7 +212,7 @@ mod tests {
             .iter()
             .find(|t| t.name == "trg_users_delete")
             .unwrap();
-        assert_eq!(insert_trigger.schema_name, "public");
+        assert_eq!(insert_trigger.table_schema, "public");
         assert_eq!(insert_trigger.table_name, "users");
         assert_eq!(delete_trigger.timing, TriggerTiming::Before);
         assert_eq!(delete_trigger.affected, TriggerAffected::Row);
@@ -275,7 +278,7 @@ mod tests {
             .iter()
             .find(|t| t.name == "trg_docs_instead_update")
             .unwrap();
-        assert_eq!(instead_trigger.schema_name, "public");
+        assert_eq!(instead_trigger.table_schema, "public");
         assert_eq!(instead_trigger.table_name, "docs_view");
         assert_eq!(instead_trigger.timing, TriggerTiming::Instead);
         assert_eq!(instead_trigger.affected, TriggerAffected::Row);
@@ -286,7 +289,7 @@ mod tests {
             .iter()
             .find(|t| t.name == "trg_docs_truncate")
             .unwrap();
-        assert_eq!(truncate_trigger.schema_name, "public");
+        assert_eq!(truncate_trigger.table_schema, "public");
         assert_eq!(truncate_trigger.table_name, "docs");
         assert_eq!(truncate_trigger.timing, TriggerTiming::After);
         assert_eq!(truncate_trigger.affected, TriggerAffected::Statement);
diff --git a/crates/pgt_statement_splitter/Cargo.toml b/crates/pgt_statement_splitter/Cargo.toml
index bdd892a60..45a42ebc6 100644
--- a/crates/pgt_statement_splitter/Cargo.toml
+++ b/crates/pgt_statement_splitter/Cargo.toml
@@ -14,7 +14,7 @@ version              = "0.0.0"
 [dependencies]
 pgt_diagnostics         = { workspace = true }
 pgt_lexer.workspace     = true
-pgt_query_ext.workspace = true
+pgt_query.workspace     = true
 pgt_text_size.workspace = true
 regex.workspace         = true
 
diff --git a/crates/pgt_statement_splitter/src/lib.rs b/crates/pgt_statement_splitter/src/lib.rs
index 19b2f230c..02ca1b304 100644
--- a/crates/pgt_statement_splitter/src/lib.rs
+++ b/crates/pgt_statement_splitter/src/lib.rs
@@ -114,6 +114,14 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_crash_eof() {
+        Tester::from("CREATE INDEX \"idx_analytics_read_ratio\" ON \"public\".\"message\" USING \"btree\" (\"inbox_id\", \"timestamp\") INCLUDE (\"status\") WHERE (\"is_inbound\" = false and channel_type not in ('postal'', 'sms'));")
+            .expect_statements(vec![
+                "CREATE INDEX \"idx_analytics_read_ratio\" ON \"public\".\"message\" USING \"btree\" (\"inbox_id\", \"timestamp\") INCLUDE (\"status\") WHERE (\"is_inbound\" = false and channel_type not in ('postal'', 'sms'));",
+            ]);
+    }
+
     #[test]
     #[timeout(1000)]
     fn basic() {
diff --git a/crates/pgt_statement_splitter/src/splitter/common.rs b/crates/pgt_statement_splitter/src/splitter/common.rs
index 9c3dea48f..786c24788 100644
--- a/crates/pgt_statement_splitter/src/splitter/common.rs
+++ b/crates/pgt_statement_splitter/src/splitter/common.rs
@@ -70,7 +70,9 @@ pub(crate) fn parenthesis(p: &mut Splitter) {
                 depth += 1;
             }
             SyntaxKind::R_PAREN | SyntaxKind::EOF => {
-                p.advance();
+                if p.current() == SyntaxKind::R_PAREN {
+                    p.advance();
+                }
                 depth -= 1;
                 if depth == 0 {
                     break;
diff --git a/crates/pgt_test_utils/src/lib.rs b/crates/pgt_test_utils/src/lib.rs
index e21c6ce4b..11bb1aebe 100644
--- a/crates/pgt_test_utils/src/lib.rs
+++ b/crates/pgt_test_utils/src/lib.rs
@@ -1 +1,85 @@
+use std::fmt::Display;
+
 pub static MIGRATIONS: sqlx::migrate::Migrator = sqlx::migrate!("./testdb_migrations");
+
+static CURSOR_POS: char = '€';
+
+#[derive(Clone)]
+pub struct QueryWithCursorPosition {
+    sql: String,
+    position: usize,
+}
+
+impl QueryWithCursorPosition {
+    pub fn cursor_marker() -> char {
+        CURSOR_POS
+    }
+
+    pub fn get_text_and_position(&self) -> (usize, String) {
+        (self.position, self.sql.clone())
+    }
+}
+
+impl From<String> for QueryWithCursorPosition {
+    fn from(value: String) -> Self {
+        value.as_str().into()
+    }
+}
+
+impl From<&str> for QueryWithCursorPosition {
+    fn from(value: &str) -> Self {
+        let position = value
+            .find(CURSOR_POS)
+            .expect("Use `QueryWithCursorPosition::cursor_marker()` to insert cursor position into your Query.");
+
+        QueryWithCursorPosition {
+            sql: value.replace(CURSOR_POS, "").trim().to_string(),
+            position,
+        }
+    }
+}
+
+impl Display for QueryWithCursorPosition {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.sql)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::QueryWithCursorPosition;
+
+    #[test]
+    fn input_query_should_extract_correct_position() {
+        struct TestCase {
+            query: String,
+            expected_pos: usize,
+            expected_sql_len: usize,
+        }
+
+        let cases = vec![
+            TestCase {
+                query: format!("select * from{}", QueryWithCursorPosition::cursor_marker()),
+                expected_pos: 13,
+                expected_sql_len: 13,
+            },
+            TestCase {
+                query: format!("{}select * from", QueryWithCursorPosition::cursor_marker()),
+                expected_pos: 0,
+                expected_sql_len: 13,
+            },
+            TestCase {
+                query: format!("select {} from", QueryWithCursorPosition::cursor_marker()),
+                expected_pos: 7,
+                expected_sql_len: 12,
+            },
+        ];
+
+        for case in cases {
+            let query = QueryWithCursorPosition::from(case.query.as_str());
+            assert_eq!(query.position, case.expected_pos);
+            assert_eq!(query.sql.len(), case.expected_sql_len);
+        }
+    }
+}
diff --git a/crates/pgt_treesitter_queries/Cargo.toml b/crates/pgt_treesitter/Cargo.toml
similarity index 54%
rename from crates/pgt_treesitter_queries/Cargo.toml
rename to crates/pgt_treesitter/Cargo.toml
index 5806861f5..f2d8b46e1 100644
--- a/crates/pgt_treesitter_queries/Cargo.toml
+++ b/crates/pgt_treesitter/Cargo.toml
@@ -6,17 +6,20 @@ edition.workspace    = true
 homepage.workspace   = true
 keywords.workspace   = true
 license.workspace    = true
-name                 = "pgt_treesitter_queries"
+name                 = "pgt_treesitter"
 repository.workspace = true
 version              = "0.0.0"
 
 
 [dependencies]
-clap                      = { version = "4.5.23", features = ["derive"] }
-tree-sitter.workspace     = true
-tree_sitter_sql.workspace = true
+clap                       = { version = "4.5.23", features = ["derive"] }
+pgt_schema_cache.workspace = true
+pgt_text_size.workspace    = true
+tree-sitter.workspace      = true
+tree_sitter_sql.workspace  = true
 
 [dev-dependencies]
+pgt_test_utils.workspace = true
 
 [lib]
 doctest = false
diff --git a/crates/pgt_completions/src/context/base_parser.rs b/crates/pgt_treesitter/src/context/base_parser.rs
similarity index 100%
rename from crates/pgt_completions/src/context/base_parser.rs
rename to crates/pgt_treesitter/src/context/base_parser.rs
diff --git a/crates/pgt_completions/src/context/grant_parser.rs b/crates/pgt_treesitter/src/context/grant_parser.rs
similarity index 94%
rename from crates/pgt_completions/src/context/grant_parser.rs
rename to crates/pgt_treesitter/src/context/grant_parser.rs
index 14ba882ae..c9aebc33b 100644
--- a/crates/pgt_completions/src/context/grant_parser.rs
+++ b/crates/pgt_treesitter/src/context/grant_parser.rs
@@ -187,14 +187,15 @@ mod tests {
     use crate::{
         context::base_parser::CompletionStatementParser,
         context::grant_parser::{GrantContext, GrantParser},
-        test_helper::CURSOR_POS,
     };
 
+    use pgt_test_utils::QueryWithCursorPosition;
+
     fn with_pos(query: String) -> (usize, String) {
         let mut pos: Option<usize> = None;
 
         for (p, c) in query.char_indices() {
-            if c == CURSOR_POS {
+            if c == QueryWithCursorPosition::cursor_marker() {
                 pos = Some(p);
                 break;
             }
@@ -202,7 +203,9 @@ mod tests {
 
         (
             pos.expect("Please add cursor position!"),
-            query.replace(CURSOR_POS, "REPLACED_TOKEN").to_string(),
+            query
+                .replace(QueryWithCursorPosition::cursor_marker(), "REPLACED_TOKEN")
+                .to_string(),
         )
     }
 
@@ -212,7 +215,7 @@ mod tests {
             r#"
             grant {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
@@ -235,7 +238,7 @@ mod tests {
             r#"
             grant select on {} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
@@ -258,7 +261,7 @@ mod tests {
             r#"
             grant select on table {} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
@@ -281,7 +284,7 @@ mod tests {
             r#"
             grant select on public.{} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
@@ -304,7 +307,7 @@ mod tests {
             r#"
             grant select on table public.{} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
@@ -327,7 +330,7 @@ mod tests {
             r#"
             grant select on public.users to {} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
@@ -350,7 +353,7 @@ mod tests {
             r#"
             grant select on public.{} to test_role
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
@@ -373,7 +376,7 @@ mod tests {
             r#"
             grant select on "MySchema"."MyTable" to {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
@@ -396,7 +399,7 @@ mod tests {
             r#"
             grant select on public.users to alice, {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = GrantParser::get_context(query.as_str(), pos);
diff --git a/crates/pgt_completions/src/context/mod.rs b/crates/pgt_treesitter/src/context/mod.rs
similarity index 78%
rename from crates/pgt_completions/src/context/mod.rs
rename to crates/pgt_treesitter/src/context/mod.rs
index 01e563b0a..9cfaadea1 100644
--- a/crates/pgt_completions/src/context/mod.rs
+++ b/crates/pgt_treesitter/src/context/mod.rs
@@ -7,22 +7,14 @@ mod grant_parser;
 mod policy_parser;
 mod revoke_parser;
 
-use pgt_schema_cache::SchemaCache;
-use pgt_text_size::TextRange;
-use pgt_treesitter_queries::{
-    TreeSitterQueriesExecutor,
-    queries::{self, QueryResult},
-};
-
-use crate::{
-    NodeText,
-    context::{
-        base_parser::CompletionStatementParser,
-        grant_parser::GrantParser,
-        policy_parser::{PolicyParser, PolicyStmtKind},
-        revoke_parser::RevokeParser,
-    },
-    sanitization::SanitizedCompletionParams,
+use crate::queries::{self, QueryResult, TreeSitterQueriesExecutor};
+use pgt_text_size::{TextRange, TextSize};
+
+use crate::context::{
+    base_parser::CompletionStatementParser,
+    grant_parser::GrantParser,
+    policy_parser::{PolicyParser, PolicyStmtKind},
+    revoke_parser::RevokeParser,
 };
 
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
@@ -59,9 +51,9 @@ pub enum WrappingClause<'a> {
 }
 
 #[derive(PartialEq, Eq, Hash, Debug, Clone)]
-pub(crate) struct MentionedColumn {
-    pub(crate) column: String,
-    pub(crate) alias: Option<String>,
+pub struct MentionedColumn {
+    pub column: String,
+    pub alias: Option<String>,
 }
 
 /// We can map a few nodes, such as the "update" node, to actual SQL clauses.
@@ -81,10 +73,10 @@ pub enum WrappingNode {
 }
 
 #[derive(Debug)]
-pub(crate) enum NodeUnderCursor<'a> {
+pub enum NodeUnderCursor<'a> {
     TsNode(tree_sitter::Node<'a>),
     CustomNode {
-        text: NodeText,
+        text: String,
         range: TextRange,
         kind: String,
         previous_node_kind: Option<String>,
@@ -150,13 +142,18 @@ impl TryFrom<String> for WrappingNode {
     }
 }
 
+pub struct TreeSitterContextParams<'a> {
+    pub position: TextSize,
+    pub text: &'a str,
+    pub tree: &'a tree_sitter::Tree,
+}
+
 #[derive(Debug)]
-pub(crate) struct CompletionContext<'a> {
+pub struct TreesitterContext<'a> {
     pub node_under_cursor: Option<NodeUnderCursor<'a>>,
 
     pub tree: &'a tree_sitter::Tree,
     pub text: &'a str,
-    pub schema_cache: &'a SchemaCache,
     pub position: usize,
 
     /// If the cursor is on a node that uses dot notation
@@ -178,6 +175,7 @@ pub(crate) struct CompletionContext<'a> {
     ///     on u.id = i.user_id;
     /// ```
     pub schema_or_alias_name: Option<String>,
+
     pub wrapping_clause_type: Option<WrappingClause<'a>>,
 
     pub wrapping_node_kind: Option<WrappingNode>,
@@ -190,12 +188,11 @@ pub(crate) struct CompletionContext<'a> {
     pub mentioned_columns: HashMap<Option<WrappingClause<'a>>, HashSet<MentionedColumn>>,
 }
 
-impl<'a> CompletionContext<'a> {
-    pub fn new(params: &'a SanitizedCompletionParams) -> Self {
+impl<'a> TreesitterContext<'a> {
+    pub fn new(params: TreeSitterContextParams<'a>) -> Self {
         let mut ctx = Self {
-            tree: params.tree.as_ref(),
-            text: &params.text,
-            schema_cache: params.schema,
+            tree: params.tree,
+            text: params.text,
             position: usize::from(params.position),
             node_under_cursor: None,
             schema_or_alias_name: None,
@@ -211,11 +208,11 @@ impl<'a> CompletionContext<'a> {
         // policy handling is important to Supabase, but they are a PostgreSQL specific extension,
         // so the tree_sitter_sql language does not support it.
         // We infer the context manually.
-        if PolicyParser::looks_like_matching_stmt(&params.text) {
+        if PolicyParser::looks_like_matching_stmt(params.text) {
             ctx.gather_policy_context();
-        } else if GrantParser::looks_like_matching_stmt(&params.text) {
+        } else if GrantParser::looks_like_matching_stmt(params.text) {
             ctx.gather_grant_context();
-        } else if RevokeParser::looks_like_matching_stmt(&params.text) {
+        } else if RevokeParser::looks_like_matching_stmt(params.text) {
             ctx.gather_revoke_context();
         } else {
             ctx.gather_tree_context();
@@ -229,7 +226,7 @@ impl<'a> CompletionContext<'a> {
         let revoke_context = RevokeParser::get_context(self.text, self.position);
 
         self.node_under_cursor = Some(NodeUnderCursor::CustomNode {
-            text: revoke_context.node_text.into(),
+            text: revoke_context.node_text,
             range: revoke_context.node_range,
             kind: revoke_context.node_kind.clone(),
             previous_node_kind: None,
@@ -257,7 +254,7 @@ impl<'a> CompletionContext<'a> {
         let grant_context = GrantParser::get_context(self.text, self.position);
 
         self.node_under_cursor = Some(NodeUnderCursor::CustomNode {
-            text: grant_context.node_text.into(),
+            text: grant_context.node_text,
             range: grant_context.node_range,
             kind: grant_context.node_kind.clone(),
             previous_node_kind: None,
@@ -285,7 +282,7 @@ impl<'a> CompletionContext<'a> {
         let policy_context = PolicyParser::get_context(self.text, self.position);
 
         self.node_under_cursor = Some(NodeUnderCursor::CustomNode {
-            text: policy_context.node_text.into(),
+            text: policy_context.node_text,
             range: policy_context.node_range,
             kind: policy_context.node_kind.clone(),
             previous_node_kind: Some(policy_context.previous_node_kind),
@@ -397,29 +394,18 @@ impl<'a> CompletionContext<'a> {
         }
     }
 
-    fn get_ts_node_content(&self, ts_node: &tree_sitter::Node<'a>) -> Option<NodeText> {
+    fn get_ts_node_content(&self, ts_node: &tree_sitter::Node<'a>) -> Option<String> {
         let source = self.text;
-        ts_node.utf8_text(source.as_bytes()).ok().map(|txt| {
-            if SanitizedCompletionParams::is_sanitized_token(txt) {
-                NodeText::Replaced
-            } else {
-                NodeText::Original(txt.into())
-            }
-        })
+        ts_node
+            .utf8_text(source.as_bytes())
+            .ok()
+            .map(|txt| txt.into())
     }
 
     pub fn get_node_under_cursor_content(&self) -> Option<String> {
         match self.node_under_cursor.as_ref()? {
-            NodeUnderCursor::TsNode(node) => {
-                self.get_ts_node_content(node).and_then(|nt| match nt {
-                    NodeText::Replaced => None,
-                    NodeText::Original(c) => Some(c.to_string()),
-                })
-            }
-            NodeUnderCursor::CustomNode { text, .. } => match text {
-                NodeText::Replaced => None,
-                NodeText::Original(c) => Some(c.to_string()),
-            },
+            NodeUnderCursor::TsNode(node) => self.get_ts_node_content(node),
+            NodeUnderCursor::CustomNode { text, .. } => Some(text.clone()),
         }
     }
 
@@ -501,15 +487,10 @@ impl<'a> CompletionContext<'a> {
         match current_node_kind {
             "object_reference" | "field" => {
                 let content = self.get_ts_node_content(&current_node);
-                if let Some(node_txt) = content {
-                    match node_txt {
-                        NodeText::Original(txt) => {
-                            let parts: Vec<&str> = txt.split('.').collect();
-                            if parts.len() == 2 {
-                                self.schema_or_alias_name = Some(parts[0].to_string());
-                            }
-                        }
-                        NodeText::Replaced => {}
+                if let Some(txt) = content {
+                    let parts: Vec<&str> = txt.split('.').collect();
+                    if parts.len() == 2 {
+                        self.schema_or_alias_name = Some(parts[0].to_string());
                     }
                 }
             }
@@ -638,12 +619,7 @@ impl<'a> CompletionContext<'a> {
                         break;
                     }
 
-                    if let Some(sibling_content) =
-                        self.get_ts_node_content(&sib).and_then(|txt| match txt {
-                            NodeText::Original(txt) => Some(txt),
-                            NodeText::Replaced => None,
-                        })
-                    {
+                    if let Some(sibling_content) = self.get_ts_node_content(&sib) {
                         if sibling_content == tokens[idx] {
                             idx += 1;
                         }
@@ -674,9 +650,7 @@ impl<'a> CompletionContext<'a> {
                     while let Some(sib) = first_sibling.next_sibling() {
                         match sib.kind() {
                             "object_reference" => {
-                                if let Some(NodeText::Original(txt)) =
-                                    self.get_ts_node_content(&sib)
-                                {
+                                if let Some(txt) = self.get_ts_node_content(&sib) {
                                     let mut iter = txt.split('.').rev();
                                     let table = iter.next().unwrap().to_string();
                                     let schema = iter.next().map(|s| s.to_string());
@@ -690,9 +664,7 @@ impl<'a> CompletionContext<'a> {
                             }
 
                             "column" => {
-                                if let Some(NodeText::Original(txt)) =
-                                    self.get_ts_node_content(&sib)
-                                {
+                                if let Some(txt) = self.get_ts_node_content(&sib) {
                                     let entry = MentionedColumn {
                                         column: txt,
                                         alias: None,
@@ -717,7 +689,7 @@ impl<'a> CompletionContext<'a> {
                 WrappingClause::AlterColumn => {
                     while let Some(sib) = first_sibling.next_sibling() {
                         if sib.kind() == "object_reference" {
-                            if let Some(NodeText::Original(txt)) = self.get_ts_node_content(&sib) {
+                            if let Some(txt) = self.get_ts_node_content(&sib) {
                                 let mut iter = txt.split('.').rev();
                                 let table = iter.next().unwrap().to_string();
                                 let schema = iter.next().map(|s| s.to_string());
@@ -777,7 +749,7 @@ impl<'a> CompletionContext<'a> {
         }
     }
 
-    pub(crate) fn parent_matches_one_of_kind(&self, kinds: &[&'static str]) -> bool {
+    pub fn parent_matches_one_of_kind(&self, kinds: &[&'static str]) -> bool {
         self.node_under_cursor
             .as_ref()
             .is_some_and(|under_cursor| match under_cursor {
@@ -788,7 +760,7 @@ impl<'a> CompletionContext<'a> {
                 NodeUnderCursor::CustomNode { .. } => false,
             })
     }
-    pub(crate) fn before_cursor_matches_kind(&self, kinds: &[&'static str]) -> bool {
+    pub fn before_cursor_matches_kind(&self, kinds: &[&'static str]) -> bool {
         self.node_under_cursor.as_ref().is_some_and(|under_cursor| {
             match under_cursor {
                 NodeUnderCursor::TsNode(node) => {
@@ -816,12 +788,9 @@ impl<'a> CompletionContext<'a> {
 
 #[cfg(test)]
 mod tests {
-    use crate::{
-        NodeText,
-        context::{CompletionContext, WrappingClause},
-        sanitization::SanitizedCompletionParams,
-        test_helper::{CURSOR_POS, get_text_and_position},
-    };
+    use crate::context::{TreeSitterContextParams, TreesitterContext, WrappingClause};
+
+    use pgt_test_utils::QueryWithCursorPosition;
 
     use super::NodeUnderCursor;
 
@@ -838,56 +807,82 @@ mod tests {
     fn identifies_clauses() {
         let test_cases = vec![
             (
-                format!("Select {}* from users;", CURSOR_POS),
+                format!(
+                    "Select {}* from users;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::Select,
             ),
             (
-                format!("Select * from u{};", CURSOR_POS),
+                format!(
+                    "Select * from u{};",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::From,
             ),
             (
-                format!("Select {}* from users where n = 1;", CURSOR_POS),
+                format!(
+                    "Select {}* from users where n = 1;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::Select,
             ),
             (
-                format!("Select * from users where {}n = 1;", CURSOR_POS),
+                format!(
+                    "Select * from users where {}n = 1;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::Where,
             ),
             (
-                format!("update users set u{} = 1 where n = 2;", CURSOR_POS),
+                format!(
+                    "update users set u{} = 1 where n = 2;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::Update,
             ),
             (
-                format!("update users set u = 1 where n{} = 2;", CURSOR_POS),
+                format!(
+                    "update users set u = 1 where n{} = 2;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::Where,
             ),
             (
-                format!("delete{} from users;", CURSOR_POS),
+                format!(
+                    "delete{} from users;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::Delete,
             ),
             (
-                format!("delete from {}users;", CURSOR_POS),
+                format!(
+                    "delete from {}users;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::From,
             ),
             (
-                format!("select name, age, location from public.u{}sers", CURSOR_POS),
+                format!(
+                    "select name, age, location from public.u{}sers",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 WrappingClause::From,
             ),
         ];
 
         for (query, expected_clause) in test_cases {
-            let (position, text) = get_text_and_position(query.as_str().into());
+            let (position, text) = QueryWithCursorPosition::from(query).get_text_and_position();
 
             let tree = get_tree(text.as_str());
 
-            let params = SanitizedCompletionParams {
+            let params = TreeSitterContextParams {
                 position: (position as u32).into(),
-                text,
-                tree: std::borrow::Cow::Owned(tree),
-                schema: &pgt_schema_cache::SchemaCache::default(),
+                text: &text,
+                tree: &tree,
             };
 
-            let ctx = CompletionContext::new(&params);
+            let ctx = TreesitterContext::new(params);
 
             assert_eq!(ctx.wrapping_clause_type, Some(expected_clause));
         }
@@ -897,29 +892,46 @@ mod tests {
     fn identifies_schema() {
         let test_cases = vec![
             (
-                format!("Select * from private.u{}", CURSOR_POS),
+                format!(
+                    "Select * from private.u{}",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 Some("private"),
             ),
             (
-                format!("Select * from private.u{}sers()", CURSOR_POS),
+                format!(
+                    "Select * from private.u{}sers()",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 Some("private"),
             ),
-            (format!("Select * from u{}sers", CURSOR_POS), None),
-            (format!("Select * from u{}sers()", CURSOR_POS), None),
+            (
+                format!(
+                    "Select * from u{}sers",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                None,
+            ),
+            (
+                format!(
+                    "Select * from u{}sers()",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                None,
+            ),
         ];
 
         for (query, expected_schema) in test_cases {
-            let (position, text) = get_text_and_position(query.as_str().into());
+            let (position, text) = QueryWithCursorPosition::from(query).get_text_and_position();
 
             let tree = get_tree(text.as_str());
-            let params = SanitizedCompletionParams {
+            let params = TreeSitterContextParams {
                 position: (position as u32).into(),
-                text,
-                tree: std::borrow::Cow::Owned(tree),
-                schema: &pgt_schema_cache::SchemaCache::default(),
+                text: &text,
+                tree: &tree,
             };
 
-            let ctx = CompletionContext::new(&params);
+            let ctx = TreesitterContext::new(params);
 
             assert_eq!(
                 ctx.schema_or_alias_name,
@@ -931,32 +943,55 @@ mod tests {
     #[test]
     fn identifies_invocation() {
         let test_cases = vec![
-            (format!("Select * from u{}sers", CURSOR_POS), false),
-            (format!("Select * from u{}sers()", CURSOR_POS), true),
-            (format!("Select cool{};", CURSOR_POS), false),
-            (format!("Select cool{}();", CURSOR_POS), true),
             (
-                format!("Select upp{}ercase as title from users;", CURSOR_POS),
+                format!(
+                    "Select * from u{}sers",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                false,
+            ),
+            (
+                format!(
+                    "Select * from u{}sers()",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
+                true,
+            ),
+            (
+                format!("Select cool{};", QueryWithCursorPosition::cursor_marker()),
+                false,
+            ),
+            (
+                format!("Select cool{}();", QueryWithCursorPosition::cursor_marker()),
+                true,
+            ),
+            (
+                format!(
+                    "Select upp{}ercase as title from users;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 false,
             ),
             (
-                format!("Select upp{}ercase(name) as title from users;", CURSOR_POS),
+                format!(
+                    "Select upp{}ercase(name) as title from users;",
+                    QueryWithCursorPosition::cursor_marker()
+                ),
                 true,
             ),
         ];
 
         for (query, is_invocation) in test_cases {
-            let (position, text) = get_text_and_position(query.as_str().into());
+            let (position, text) = QueryWithCursorPosition::from(query).get_text_and_position();
 
             let tree = get_tree(text.as_str());
-            let params = SanitizedCompletionParams {
+            let params = TreeSitterContextParams {
                 position: (position as u32).into(),
-                text,
-                tree: std::borrow::Cow::Owned(tree),
-                schema: &pgt_schema_cache::SchemaCache::default(),
+                text: text.as_str(),
+                tree: &tree,
             };
 
-            let ctx = CompletionContext::new(&params);
+            let ctx = TreesitterContext::new(params);
 
             assert_eq!(ctx.is_invocation, is_invocation);
         }
@@ -965,32 +1000,34 @@ mod tests {
     #[test]
     fn does_not_fail_on_leading_whitespace() {
         let cases = vec![
-            format!("{}      select * from", CURSOR_POS),
-            format!(" {}      select * from", CURSOR_POS),
+            format!(
+                "{}      select * from",
+                QueryWithCursorPosition::cursor_marker()
+            ),
+            format!(
+                " {}      select * from",
+                QueryWithCursorPosition::cursor_marker()
+            ),
         ];
 
         for query in cases {
-            let (position, text) = get_text_and_position(query.as_str().into());
+            let (position, text) = QueryWithCursorPosition::from(query).get_text_and_position();
 
             let tree = get_tree(text.as_str());
 
-            let params = SanitizedCompletionParams {
+            let params = TreeSitterContextParams {
                 position: (position as u32).into(),
-                text,
-                tree: std::borrow::Cow::Owned(tree),
-                schema: &pgt_schema_cache::SchemaCache::default(),
+                text: &text,
+                tree: &tree,
             };
 
-            let ctx = CompletionContext::new(&params);
+            let ctx = TreesitterContext::new(params);
 
             let node = ctx.node_under_cursor.as_ref().unwrap();
 
             match node {
                 NodeUnderCursor::TsNode(node) => {
-                    assert_eq!(
-                        ctx.get_ts_node_content(node),
-                        Some(NodeText::Original("select".into()))
-                    );
+                    assert_eq!(ctx.get_ts_node_content(node), Some("select".into()));
 
                     assert_eq!(
                         ctx.wrapping_clause_type,
@@ -1004,29 +1041,28 @@ mod tests {
 
     #[test]
     fn does_not_fail_on_trailing_whitespace() {
-        let query = format!("select * from   {}", CURSOR_POS);
+        let query = format!(
+            "select * from   {}",
+            QueryWithCursorPosition::cursor_marker()
+        );
 
-        let (position, text) = get_text_and_position(query.as_str().into());
+        let (position, text) = QueryWithCursorPosition::from(query).get_text_and_position();
 
         let tree = get_tree(text.as_str());
 
-        let params = SanitizedCompletionParams {
+        let params = TreeSitterContextParams {
             position: (position as u32).into(),
-            text,
-            tree: std::borrow::Cow::Owned(tree),
-            schema: &pgt_schema_cache::SchemaCache::default(),
+            text: &text,
+            tree: &tree,
         };
 
-        let ctx = CompletionContext::new(&params);
+        let ctx = TreesitterContext::new(params);
 
         let node = ctx.node_under_cursor.as_ref().unwrap();
 
         match node {
             NodeUnderCursor::TsNode(node) => {
-                assert_eq!(
-                    ctx.get_ts_node_content(node),
-                    Some(NodeText::Original("from".into()))
-                );
+                assert_eq!(ctx.get_ts_node_content(node), Some("from".into()));
             }
             _ => unreachable!(),
         }
@@ -1034,29 +1070,25 @@ mod tests {
 
     #[test]
     fn does_not_fail_with_empty_statements() {
-        let query = format!("{}", CURSOR_POS);
+        let query = format!("{}", QueryWithCursorPosition::cursor_marker());
 
-        let (position, text) = get_text_and_position(query.as_str().into());
+        let (position, text) = QueryWithCursorPosition::from(query).get_text_and_position();
 
         let tree = get_tree(text.as_str());
 
-        let params = SanitizedCompletionParams {
+        let params = TreeSitterContextParams {
             position: (position as u32).into(),
-            text,
-            tree: std::borrow::Cow::Owned(tree),
-            schema: &pgt_schema_cache::SchemaCache::default(),
+            text: &text,
+            tree: &tree,
         };
 
-        let ctx = CompletionContext::new(&params);
+        let ctx = TreesitterContext::new(params);
 
         let node = ctx.node_under_cursor.as_ref().unwrap();
 
         match node {
             NodeUnderCursor::TsNode(node) => {
-                assert_eq!(
-                    ctx.get_ts_node_content(node),
-                    Some(NodeText::Original("".into()))
-                );
+                assert_eq!(ctx.get_ts_node_content(node), Some("".into()));
                 assert_eq!(ctx.wrapping_clause_type, None);
             }
             _ => unreachable!(),
@@ -1067,29 +1099,25 @@ mod tests {
     fn does_not_fail_on_incomplete_keywords() {
         //  Instead of autocompleting "FROM", we'll assume that the user
         // is selecting a certain column name, such as `frozen_account`.
-        let query = format!("select * fro{}", CURSOR_POS);
+        let query = format!("select * fro{}", QueryWithCursorPosition::cursor_marker());
 
-        let (position, text) = get_text_and_position(query.as_str().into());
+        let (position, text) = QueryWithCursorPosition::from(query).get_text_and_position();
 
         let tree = get_tree(text.as_str());
 
-        let params = SanitizedCompletionParams {
+        let params = TreeSitterContextParams {
             position: (position as u32).into(),
-            text,
-            tree: std::borrow::Cow::Owned(tree),
-            schema: &pgt_schema_cache::SchemaCache::default(),
+            text: &text,
+            tree: &tree,
         };
 
-        let ctx = CompletionContext::new(&params);
+        let ctx = TreesitterContext::new(params);
 
         let node = ctx.node_under_cursor.as_ref().unwrap();
 
         match node {
             NodeUnderCursor::TsNode(node) => {
-                assert_eq!(
-                    ctx.get_ts_node_content(node),
-                    Some(NodeText::Original("fro".into()))
-                );
+                assert_eq!(ctx.get_ts_node_content(node), Some("fro".into()));
                 assert_eq!(ctx.wrapping_clause_type, Some(WrappingClause::Select));
             }
             _ => unreachable!(),
diff --git a/crates/pgt_completions/src/context/policy_parser.rs b/crates/pgt_treesitter/src/context/policy_parser.rs
similarity index 95%
rename from crates/pgt_completions/src/context/policy_parser.rs
rename to crates/pgt_treesitter/src/context/policy_parser.rs
index bcc604990..776645163 100644
--- a/crates/pgt_completions/src/context/policy_parser.rs
+++ b/crates/pgt_treesitter/src/context/policy_parser.rs
@@ -212,16 +212,17 @@ mod tests {
     use crate::{
         context::base_parser::CompletionStatementParser,
         context::policy_parser::{PolicyContext, PolicyStmtKind},
-        test_helper::CURSOR_POS,
     };
 
+    use pgt_test_utils::QueryWithCursorPosition;
+
     use super::PolicyParser;
 
     fn with_pos(query: String) -> (usize, String) {
         let mut pos: Option<usize> = None;
 
         for (p, c) in query.char_indices() {
-            if c == CURSOR_POS {
+            if c == QueryWithCursorPosition::cursor_marker() {
                 pos = Some(p);
                 break;
             }
@@ -229,7 +230,9 @@ mod tests {
 
         (
             pos.expect("Please add cursor position!"),
-            query.replace(CURSOR_POS, "REPLACED_TOKEN").to_string(),
+            query
+                .replace(QueryWithCursorPosition::cursor_marker(), "REPLACED_TOKEN")
+                .to_string(),
         )
     }
 
@@ -239,7 +242,7 @@ mod tests {
             r#"
           create policy {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -265,7 +268,7 @@ mod tests {
             r#"
           create policy "my cool policy" {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -291,7 +294,7 @@ mod tests {
             r#"
           create policy "my cool policy" on {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -317,7 +320,7 @@ mod tests {
             r#"
           create policy "my cool policy" on auth.{}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -344,7 +347,7 @@ mod tests {
           create policy "my cool policy" on auth.users 
             as {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -372,7 +375,7 @@ mod tests {
             as permissive
             {} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -400,7 +403,7 @@ mod tests {
             as permissive
             to {} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -432,7 +435,7 @@ mod tests {
             to all 
             using (true);
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -464,7 +467,7 @@ mod tests {
             to all 
             using (true);
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -493,7 +496,7 @@ mod tests {
             r#"
           drop policy {} on auth.users;
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -520,7 +523,7 @@ mod tests {
             r#"
           drop policy "{}" on auth.users;
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -549,7 +552,7 @@ mod tests {
             r#"
           drop policy "{} on auth.users;
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = PolicyParser::get_context(query.as_str(), pos);
@@ -567,7 +570,7 @@ mod tests {
             to all 
             using (id = {})
         "#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ));
 
             let context = PolicyParser::get_context(query.as_str(), pos);
@@ -598,7 +601,7 @@ mod tests {
             to all
             using ({}
         "#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ));
 
             let context = PolicyParser::get_context(query.as_str(), pos);
@@ -629,7 +632,7 @@ mod tests {
             to all
             with check ({}
         "#,
-                CURSOR_POS
+                QueryWithCursorPosition::cursor_marker()
             ));
 
             let context = PolicyParser::get_context(query.as_str(), pos);
diff --git a/crates/pgt_completions/src/context/revoke_parser.rs b/crates/pgt_treesitter/src/context/revoke_parser.rs
similarity index 94%
rename from crates/pgt_completions/src/context/revoke_parser.rs
rename to crates/pgt_treesitter/src/context/revoke_parser.rs
index e0c43934c..4f5b09ec8 100644
--- a/crates/pgt_completions/src/context/revoke_parser.rs
+++ b/crates/pgt_treesitter/src/context/revoke_parser.rs
@@ -180,14 +180,15 @@ mod tests {
     use crate::{
         context::base_parser::CompletionStatementParser,
         context::revoke_parser::{RevokeContext, RevokeParser},
-        test_helper::CURSOR_POS,
     };
 
+    use pgt_test_utils::QueryWithCursorPosition;
+
     fn with_pos(query: String) -> (usize, String) {
         let mut pos: Option<usize> = None;
 
         for (p, c) in query.char_indices() {
-            if c == CURSOR_POS {
+            if c == QueryWithCursorPosition::cursor_marker() {
                 pos = Some(p);
                 break;
             }
@@ -195,7 +196,9 @@ mod tests {
 
         (
             pos.expect("Please add cursor position!"),
-            query.replace(CURSOR_POS, "REPLACED_TOKEN").to_string(),
+            query
+                .replace(QueryWithCursorPosition::cursor_marker(), "REPLACED_TOKEN")
+                .to_string(),
         )
     }
 
@@ -205,7 +208,7 @@ mod tests {
             r#"
             revoke {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = RevokeParser::get_context(query.as_str(), pos);
@@ -228,7 +231,7 @@ mod tests {
             r#"
             revoke select on {} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = RevokeParser::get_context(query.as_str(), pos);
@@ -251,7 +254,7 @@ mod tests {
             r#"
             revoke select on public.{} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = RevokeParser::get_context(query.as_str(), pos);
@@ -274,7 +277,7 @@ mod tests {
             r#"
             revoke select on public.users from {} 
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = RevokeParser::get_context(query.as_str(), pos);
@@ -297,7 +300,7 @@ mod tests {
             r#"
             revoke select on public.users from alice, {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = RevokeParser::get_context(query.as_str(), pos);
@@ -320,7 +323,7 @@ mod tests {
             r#"
             revoke select on "MySchema"."MyTable" from {}
         "#,
-            CURSOR_POS
+            QueryWithCursorPosition::cursor_marker()
         ));
 
         let context = RevokeParser::get_context(query.as_str(), pos);
diff --git a/crates/pgt_treesitter/src/lib.rs b/crates/pgt_treesitter/src/lib.rs
new file mode 100644
index 000000000..6b19db53a
--- /dev/null
+++ b/crates/pgt_treesitter/src/lib.rs
@@ -0,0 +1,5 @@
+pub mod context;
+pub mod queries;
+
+pub use context::*;
+pub use queries::*;
diff --git a/crates/pgt_treesitter_queries/src/queries/insert_columns.rs b/crates/pgt_treesitter/src/queries/insert_columns.rs
similarity index 97%
rename from crates/pgt_treesitter_queries/src/queries/insert_columns.rs
rename to crates/pgt_treesitter/src/queries/insert_columns.rs
index 3e88d998f..94d67b690 100644
--- a/crates/pgt_treesitter_queries/src/queries/insert_columns.rs
+++ b/crates/pgt_treesitter/src/queries/insert_columns.rs
@@ -1,6 +1,6 @@
 use std::sync::LazyLock;
 
-use crate::{Query, QueryResult};
+use crate::queries::{Query, QueryResult};
 
 use super::QueryTryFrom;
 
@@ -51,7 +51,7 @@ impl<'a> QueryTryFrom<'a> for InsertColumnMatch<'a> {
 }
 
 impl<'a> Query<'a> for InsertColumnMatch<'a> {
-    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<crate::QueryResult<'a>> {
+    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<QueryResult<'a>> {
         let mut cursor = tree_sitter::QueryCursor::new();
 
         let matches = cursor.matches(&TS_QUERY, root_node, stmt.as_bytes());
@@ -73,7 +73,7 @@ impl<'a> Query<'a> for InsertColumnMatch<'a> {
 #[cfg(test)]
 mod tests {
     use super::InsertColumnMatch;
-    use crate::TreeSitterQueriesExecutor;
+    use crate::queries::TreeSitterQueriesExecutor;
 
     #[test]
     fn finds_all_insert_columns() {
diff --git a/crates/pgt_treesitter_queries/src/lib.rs b/crates/pgt_treesitter/src/queries/mod.rs
similarity index 72%
rename from crates/pgt_treesitter_queries/src/lib.rs
rename to crates/pgt_treesitter/src/queries/mod.rs
index 4bf71e744..1d24f07a4 100644
--- a/crates/pgt_treesitter_queries/src/lib.rs
+++ b/crates/pgt_treesitter/src/queries/mod.rs
@@ -1,8 +1,91 @@
-pub mod queries;
+mod insert_columns;
+mod parameters;
+mod relations;
+mod select_columns;
+mod table_aliases;
+mod where_columns;
 
 use std::slice::Iter;
 
-use queries::{Query, QueryResult};
+pub use insert_columns::*;
+pub use parameters::*;
+pub use relations::*;
+pub use select_columns::*;
+pub use table_aliases::*;
+pub use where_columns::*;
+
+#[derive(Debug)]
+pub enum QueryResult<'a> {
+    Relation(RelationMatch<'a>),
+    Parameter(ParameterMatch<'a>),
+    TableAliases(TableAliasMatch<'a>),
+    SelectClauseColumns(SelectColumnMatch<'a>),
+    InsertClauseColumns(InsertColumnMatch<'a>),
+    WhereClauseColumns(WhereColumnMatch<'a>),
+}
+
+impl QueryResult<'_> {
+    pub fn within_range(&self, range: &tree_sitter::Range) -> bool {
+        match self {
+            QueryResult::Relation(rm) => {
+                let start = match rm.schema {
+                    Some(s) => s.start_position(),
+                    None => rm.table.start_position(),
+                };
+
+                let end = rm.table.end_position();
+
+                start >= range.start_point && end <= range.end_point
+            }
+            Self::Parameter(pm) => {
+                let node_range = pm.node.range();
+
+                node_range.start_point >= range.start_point
+                    && node_range.end_point <= range.end_point
+            }
+            QueryResult::TableAliases(m) => {
+                let start = m.table.start_position();
+                let end = m.alias.end_position();
+                start >= range.start_point && end <= range.end_point
+            }
+            Self::SelectClauseColumns(cm) => {
+                let start = match cm.alias {
+                    Some(n) => n.start_position(),
+                    None => cm.column.start_position(),
+                };
+
+                let end = cm.column.end_position();
+
+                start >= range.start_point && end <= range.end_point
+            }
+            Self::WhereClauseColumns(cm) => {
+                let start = match cm.alias {
+                    Some(n) => n.start_position(),
+                    None => cm.column.start_position(),
+                };
+
+                let end = cm.column.end_position();
+
+                start >= range.start_point && end <= range.end_point
+            }
+            Self::InsertClauseColumns(cm) => {
+                let start = cm.column.start_position();
+                let end = cm.column.end_position();
+                start >= range.start_point && end <= range.end_point
+            }
+        }
+    }
+}
+
+// This trait enforces that for any `Self` that implements `Query`,
+// its &Self must implement TryFrom<&QueryResult>
+pub(crate) trait QueryTryFrom<'a>: Sized {
+    type Ref: for<'any> TryFrom<&'a QueryResult<'a>, Error = String>;
+}
+
+pub(crate) trait Query<'a>: QueryTryFrom<'a> {
+    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<QueryResult<'a>>;
+}
 
 pub struct TreeSitterQueriesExecutor<'a> {
     root_node: tree_sitter::Node<'a>,
@@ -68,9 +151,8 @@ impl<'a> Iterator for QueryResultIter<'a> {
 #[cfg(test)]
 mod tests {
 
-    use crate::{
-        TreeSitterQueriesExecutor,
-        queries::{ParameterMatch, RelationMatch, TableAliasMatch},
+    use crate::queries::{
+        ParameterMatch, RelationMatch, TableAliasMatch, TreeSitterQueriesExecutor,
     };
 
     #[test]
diff --git a/crates/pgt_treesitter_queries/src/queries/parameters.rs b/crates/pgt_treesitter/src/queries/parameters.rs
similarity index 96%
rename from crates/pgt_treesitter_queries/src/queries/parameters.rs
rename to crates/pgt_treesitter/src/queries/parameters.rs
index 85ea9ad25..0b7f2e3df 100644
--- a/crates/pgt_treesitter_queries/src/queries/parameters.rs
+++ b/crates/pgt_treesitter/src/queries/parameters.rs
@@ -1,6 +1,6 @@
 use std::sync::LazyLock;
 
-use crate::{Query, QueryResult};
+use crate::queries::{Query, QueryResult};
 
 use super::QueryTryFrom;
 
@@ -59,7 +59,7 @@ impl<'a> QueryTryFrom<'a> for ParameterMatch<'a> {
 }
 
 impl<'a> Query<'a> for ParameterMatch<'a> {
-    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<crate::QueryResult<'a>> {
+    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<QueryResult<'a>> {
         let mut cursor = tree_sitter::QueryCursor::new();
 
         let matches = cursor.matches(&TS_QUERY, root_node, stmt.as_bytes());
diff --git a/crates/pgt_treesitter_queries/src/queries/relations.rs b/crates/pgt_treesitter/src/queries/relations.rs
similarity index 98%
rename from crates/pgt_treesitter_queries/src/queries/relations.rs
rename to crates/pgt_treesitter/src/queries/relations.rs
index 2d7e44317..cb6a6bea9 100644
--- a/crates/pgt_treesitter_queries/src/queries/relations.rs
+++ b/crates/pgt_treesitter/src/queries/relations.rs
@@ -1,6 +1,6 @@
 use std::sync::LazyLock;
 
-use crate::{Query, QueryResult};
+use crate::queries::{Query, QueryResult};
 
 use super::QueryTryFrom;
 
@@ -79,7 +79,7 @@ impl<'a> QueryTryFrom<'a> for RelationMatch<'a> {
 }
 
 impl<'a> Query<'a> for RelationMatch<'a> {
-    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<crate::QueryResult<'a>> {
+    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<QueryResult<'a>> {
         let mut cursor = tree_sitter::QueryCursor::new();
 
         let matches = cursor.matches(&TS_QUERY, root_node, stmt.as_bytes());
@@ -112,8 +112,9 @@ impl<'a> Query<'a> for RelationMatch<'a> {
 
 #[cfg(test)]
 mod tests {
+    use crate::queries::TreeSitterQueriesExecutor;
+
     use super::RelationMatch;
-    use crate::TreeSitterQueriesExecutor;
 
     #[test]
     fn finds_table_without_schema() {
diff --git a/crates/pgt_treesitter_queries/src/queries/select_columns.rs b/crates/pgt_treesitter/src/queries/select_columns.rs
similarity index 97%
rename from crates/pgt_treesitter_queries/src/queries/select_columns.rs
rename to crates/pgt_treesitter/src/queries/select_columns.rs
index 00b6977d0..f232abc38 100644
--- a/crates/pgt_treesitter_queries/src/queries/select_columns.rs
+++ b/crates/pgt_treesitter/src/queries/select_columns.rs
@@ -1,6 +1,6 @@
 use std::sync::LazyLock;
 
-use crate::{Query, QueryResult};
+use crate::queries::{Query, QueryResult};
 
 use super::QueryTryFrom;
 
@@ -63,7 +63,7 @@ impl<'a> QueryTryFrom<'a> for SelectColumnMatch<'a> {
 }
 
 impl<'a> Query<'a> for SelectColumnMatch<'a> {
-    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<crate::QueryResult<'a>> {
+    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<QueryResult<'a>> {
         let mut cursor = tree_sitter::QueryCursor::new();
 
         let matches = cursor.matches(&TS_QUERY, root_node, stmt.as_bytes());
@@ -96,7 +96,7 @@ impl<'a> Query<'a> for SelectColumnMatch<'a> {
 
 #[cfg(test)]
 mod tests {
-    use crate::TreeSitterQueriesExecutor;
+    use crate::queries::TreeSitterQueriesExecutor;
 
     use super::SelectColumnMatch;
 
diff --git a/crates/pgt_treesitter_queries/src/queries/table_aliases.rs b/crates/pgt_treesitter/src/queries/table_aliases.rs
similarity index 97%
rename from crates/pgt_treesitter_queries/src/queries/table_aliases.rs
rename to crates/pgt_treesitter/src/queries/table_aliases.rs
index 4297a2186..70d4d52ef 100644
--- a/crates/pgt_treesitter_queries/src/queries/table_aliases.rs
+++ b/crates/pgt_treesitter/src/queries/table_aliases.rs
@@ -1,6 +1,6 @@
 use std::sync::LazyLock;
 
-use crate::{Query, QueryResult};
+use crate::queries::{Query, QueryResult};
 
 use super::QueryTryFrom;
 
@@ -69,7 +69,7 @@ impl<'a> QueryTryFrom<'a> for TableAliasMatch<'a> {
 }
 
 impl<'a> Query<'a> for TableAliasMatch<'a> {
-    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<crate::QueryResult<'a>> {
+    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<QueryResult<'a>> {
         let mut cursor = tree_sitter::QueryCursor::new();
 
         let matches = cursor.matches(&TS_QUERY, root_node, stmt.as_bytes());
diff --git a/crates/pgt_treesitter_queries/src/queries/where_columns.rs b/crates/pgt_treesitter/src/queries/where_columns.rs
similarity index 97%
rename from crates/pgt_treesitter_queries/src/queries/where_columns.rs
rename to crates/pgt_treesitter/src/queries/where_columns.rs
index 8e19590de..b683300b6 100644
--- a/crates/pgt_treesitter_queries/src/queries/where_columns.rs
+++ b/crates/pgt_treesitter/src/queries/where_columns.rs
@@ -1,6 +1,6 @@
 use std::sync::LazyLock;
 
-use crate::{Query, QueryResult};
+use crate::queries::{Query, QueryResult};
 
 use super::QueryTryFrom;
 
@@ -64,7 +64,7 @@ impl<'a> QueryTryFrom<'a> for WhereColumnMatch<'a> {
 }
 
 impl<'a> Query<'a> for WhereColumnMatch<'a> {
-    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<crate::QueryResult<'a>> {
+    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<QueryResult<'a>> {
         let mut cursor = tree_sitter::QueryCursor::new();
 
         let matches = cursor.matches(&TS_QUERY, root_node, stmt.as_bytes());
diff --git a/crates/pgt_treesitter_queries/src/queries/mod.rs b/crates/pgt_treesitter_queries/src/queries/mod.rs
deleted file mode 100644
index b9f39aed8..000000000
--- a/crates/pgt_treesitter_queries/src/queries/mod.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-mod insert_columns;
-mod parameters;
-mod relations;
-mod select_columns;
-mod table_aliases;
-mod where_columns;
-
-pub use insert_columns::*;
-pub use parameters::*;
-pub use relations::*;
-pub use select_columns::*;
-pub use table_aliases::*;
-pub use where_columns::*;
-
-#[derive(Debug)]
-pub enum QueryResult<'a> {
-    Relation(RelationMatch<'a>),
-    Parameter(ParameterMatch<'a>),
-    TableAliases(TableAliasMatch<'a>),
-    SelectClauseColumns(SelectColumnMatch<'a>),
-    InsertClauseColumns(InsertColumnMatch<'a>),
-    WhereClauseColumns(WhereColumnMatch<'a>),
-}
-
-impl QueryResult<'_> {
-    pub fn within_range(&self, range: &tree_sitter::Range) -> bool {
-        match self {
-            QueryResult::Relation(rm) => {
-                let start = match rm.schema {
-                    Some(s) => s.start_position(),
-                    None => rm.table.start_position(),
-                };
-
-                let end = rm.table.end_position();
-
-                start >= range.start_point && end <= range.end_point
-            }
-            Self::Parameter(pm) => {
-                let node_range = pm.node.range();
-
-                node_range.start_point >= range.start_point
-                    && node_range.end_point <= range.end_point
-            }
-            QueryResult::TableAliases(m) => {
-                let start = m.table.start_position();
-                let end = m.alias.end_position();
-                start >= range.start_point && end <= range.end_point
-            }
-            Self::SelectClauseColumns(cm) => {
-                let start = match cm.alias {
-                    Some(n) => n.start_position(),
-                    None => cm.column.start_position(),
-                };
-
-                let end = cm.column.end_position();
-
-                start >= range.start_point && end <= range.end_point
-            }
-            Self::WhereClauseColumns(cm) => {
-                let start = match cm.alias {
-                    Some(n) => n.start_position(),
-                    None => cm.column.start_position(),
-                };
-
-                let end = cm.column.end_position();
-
-                start >= range.start_point && end <= range.end_point
-            }
-            Self::InsertClauseColumns(cm) => {
-                let start = cm.column.start_position();
-                let end = cm.column.end_position();
-                start >= range.start_point && end <= range.end_point
-            }
-        }
-    }
-}
-
-// This trait enforces that for any `Self` that implements `Query`,
-// its &Self must implement TryFrom<&QueryResult>
-pub(crate) trait QueryTryFrom<'a>: Sized {
-    type Ref: for<'any> TryFrom<&'a QueryResult<'a>, Error = String>;
-}
-
-pub(crate) trait Query<'a>: QueryTryFrom<'a> {
-    fn execute(root_node: tree_sitter::Node<'a>, stmt: &'a str) -> Vec<crate::QueryResult<'a>>;
-}
diff --git a/crates/pgt_type_resolver/Cargo.toml b/crates/pgt_type_resolver/Cargo.toml
index 5d2a8eb15..9a190fdf4 100644
--- a/crates/pgt_type_resolver/Cargo.toml
+++ b/crates/pgt_type_resolver/Cargo.toml
@@ -12,7 +12,7 @@ version              = "0.0.0"
 
 
 [dependencies]
-pgt_query_ext.workspace    = true
+pgt_query.workspace        = true
 pgt_schema_cache.workspace = true
 
 [dev-dependencies]
diff --git a/crates/pgt_type_resolver/src/functions.rs b/crates/pgt_type_resolver/src/functions.rs
index 1b0036b56..208af30dd 100644
--- a/crates/pgt_type_resolver/src/functions.rs
+++ b/crates/pgt_type_resolver/src/functions.rs
@@ -6,7 +6,7 @@ use crate::{
 };
 
 pub fn resolve_func_call<'b>(
-    node: &pgt_query_ext::protobuf::FuncCall,
+    node: &pgt_query::protobuf::FuncCall,
     schema_cache: &'b SchemaCache,
 ) -> Option<&'b Function> {
     let (schema, name) = resolve_func_identifier(node);
@@ -30,7 +30,7 @@ pub fn resolve_func_call<'b>(
     if fns.len() == 1 { Some(fns[0]) } else { None }
 }
 
-fn resolve_func_identifier(node: &pgt_query_ext::protobuf::FuncCall) -> (Option<String>, String) {
+fn resolve_func_identifier(node: &pgt_query::protobuf::FuncCall) -> (Option<String>, String) {
     match node.funcname.as_slice() {
         [name] => (None, get_string_from_node(name)),
         [schema, name] => (
diff --git a/crates/pgt_type_resolver/src/types.rs b/crates/pgt_type_resolver/src/types.rs
index b5560114b..85e1d8d2d 100644
--- a/crates/pgt_type_resolver/src/types.rs
+++ b/crates/pgt_type_resolver/src/types.rs
@@ -5,9 +5,9 @@ pub(crate) enum PossibleType {
     AnyOf(Vec<i64>),
 }
 
-pub fn resolve_type(node: &pgt_query_ext::NodeEnum, schema_cache: &SchemaCache) -> PossibleType {
+pub fn resolve_type(node: &pgt_query::NodeEnum, schema_cache: &SchemaCache) -> PossibleType {
     match node {
-        pgt_query_ext::NodeEnum::AConst(n) => {
+        pgt_query::NodeEnum::AConst(n) => {
             if n.isnull {
                 PossibleType::Null
             } else {
@@ -16,7 +16,7 @@ pub fn resolve_type(node: &pgt_query_ext::NodeEnum, schema_cache: &SchemaCache)
                     .as_ref()
                     .expect("expected non-nullable AConst to have a value")
                 {
-                    pgt_query_ext::protobuf::a_const::Val::Ival(_) => {
+                    pgt_query::protobuf::a_const::Val::Ival(_) => {
                         let types: Vec<String> = ["int2", "int4", "int8"]
                             .iter()
                             .map(|s| s.to_string())
@@ -33,7 +33,7 @@ pub fn resolve_type(node: &pgt_query_ext::NodeEnum, schema_cache: &SchemaCache)
                                 .collect(),
                         )
                     }
-                    pgt_query_ext::protobuf::a_const::Val::Fval(_) => {
+                    pgt_query::protobuf::a_const::Val::Fval(_) => {
                         let types: Vec<String> =
                             ["float4", "float8"].iter().map(|s| s.to_string()).collect();
 
@@ -46,7 +46,7 @@ pub fn resolve_type(node: &pgt_query_ext::NodeEnum, schema_cache: &SchemaCache)
                                 .collect(),
                         )
                     }
-                    pgt_query_ext::protobuf::a_const::Val::Boolval(_) => PossibleType::AnyOf(
+                    pgt_query::protobuf::a_const::Val::Boolval(_) => PossibleType::AnyOf(
                         schema_cache
                             .types
                             .iter()
@@ -54,7 +54,7 @@ pub fn resolve_type(node: &pgt_query_ext::NodeEnum, schema_cache: &SchemaCache)
                             .map(|t| t.id)
                             .collect(),
                     ),
-                    pgt_query_ext::protobuf::a_const::Val::Sval(v) => {
+                    pgt_query::protobuf::a_const::Val::Sval(v) => {
                         let types: Vec<String> =
                             ["text", "varchar"].iter().map(|s| s.to_string()).collect();
 
@@ -70,7 +70,7 @@ pub fn resolve_type(node: &pgt_query_ext::NodeEnum, schema_cache: &SchemaCache)
                                 .collect(),
                         )
                     }
-                    pgt_query_ext::protobuf::a_const::Val::Bsval(_) => todo!(),
+                    pgt_query::protobuf::a_const::Val::Bsval(_) => todo!(),
                 }
             }
         }
diff --git a/crates/pgt_type_resolver/src/util.rs b/crates/pgt_type_resolver/src/util.rs
index f10cf5bbc..d31d1fa8f 100644
--- a/crates/pgt_type_resolver/src/util.rs
+++ b/crates/pgt_type_resolver/src/util.rs
@@ -1,6 +1,6 @@
-pub(crate) fn get_string_from_node(node: &pgt_query_ext::protobuf::Node) -> String {
+pub(crate) fn get_string_from_node(node: &pgt_query::protobuf::Node) -> String {
     match &node.node {
-        Some(pgt_query_ext::NodeEnum::String(s)) => s.sval.to_string(),
+        Some(pgt_query::NodeEnum::String(s)) => s.sval.to_string(),
         _ => "".to_string(),
     }
 }
diff --git a/crates/pgt_typecheck/Cargo.toml b/crates/pgt_typecheck/Cargo.toml
index caacc6d17..f61f6a37e 100644
--- a/crates/pgt_typecheck/Cargo.toml
+++ b/crates/pgt_typecheck/Cargo.toml
@@ -12,16 +12,16 @@ version              = "0.0.0"
 
 
 [dependencies]
-pgt_console.workspace            = true
-pgt_diagnostics.workspace        = true
-pgt_query_ext.workspace          = true
-pgt_schema_cache.workspace       = true
-pgt_text_size.workspace          = true
-pgt_treesitter_queries.workspace = true
-sqlx.workspace                   = true
-tokio.workspace                  = true
-tree-sitter.workspace            = true
-tree_sitter_sql.workspace        = true
+pgt_console.workspace      = true
+pgt_diagnostics.workspace  = true
+pgt_query.workspace        = true
+pgt_schema_cache.workspace = true
+pgt_text_size.workspace    = true
+pgt_treesitter.workspace   = true
+sqlx.workspace             = true
+tokio.workspace            = true
+tree-sitter.workspace      = true
+tree_sitter_sql.workspace  = true
 
 [dev-dependencies]
 insta.workspace          = true
diff --git a/crates/pgt_typecheck/src/lib.rs b/crates/pgt_typecheck/src/lib.rs
index e1dcd259f..ceb36b94e 100644
--- a/crates/pgt_typecheck/src/lib.rs
+++ b/crates/pgt_typecheck/src/lib.rs
@@ -3,7 +3,6 @@ mod typed_identifier;
 
 pub use diagnostics::TypecheckDiagnostic;
 use diagnostics::create_type_error;
-use pgt_text_size::TextRange;
 use sqlx::postgres::PgDatabaseError;
 pub use sqlx::postgres::PgSeverity;
 use sqlx::{Executor, PgPool};
@@ -14,36 +13,23 @@ pub use typed_identifier::{IdentifierType, TypedIdentifier};
 pub struct TypecheckParams<'a> {
     pub conn: &'a PgPool,
     pub sql: &'a str,
-    pub ast: &'a pgt_query_ext::NodeEnum,
+    pub ast: &'a pgt_query::NodeEnum,
     pub tree: &'a tree_sitter::Tree,
     pub schema_cache: &'a pgt_schema_cache::SchemaCache,
     pub identifiers: Vec<TypedIdentifier>,
 }
 
-#[derive(Debug, Clone)]
-pub struct TypeError {
-    pub message: String,
-    pub code: String,
-    pub severity: PgSeverity,
-    pub position: Option<usize>,
-    pub range: Option<TextRange>,
-    pub table: Option<String>,
-    pub column: Option<String>,
-    pub data_type: Option<String>,
-    pub constraint: Option<String>,
-}
-
 pub async fn check_sql(
     params: TypecheckParams<'_>,
 ) -> Result<Option<TypecheckDiagnostic>, sqlx::Error> {
     // Check if the AST is not a supported statement type
     if !matches!(
         params.ast,
-        pgt_query_ext::NodeEnum::SelectStmt(_)
-            | pgt_query_ext::NodeEnum::InsertStmt(_)
-            | pgt_query_ext::NodeEnum::UpdateStmt(_)
-            | pgt_query_ext::NodeEnum::DeleteStmt(_)
-            | pgt_query_ext::NodeEnum::CommonTableExpr(_)
+        pgt_query::NodeEnum::SelectStmt(_)
+            | pgt_query::NodeEnum::InsertStmt(_)
+            | pgt_query::NodeEnum::UpdateStmt(_)
+            | pgt_query::NodeEnum::DeleteStmt(_)
+            | pgt_query::NodeEnum::CommonTableExpr(_)
     ) {
         return Ok(None);
     }
diff --git a/crates/pgt_typecheck/src/typed_identifier.rs b/crates/pgt_typecheck/src/typed_identifier.rs
index 710b2fe98..1ee4095dc 100644
--- a/crates/pgt_typecheck/src/typed_identifier.rs
+++ b/crates/pgt_typecheck/src/typed_identifier.rs
@@ -1,5 +1,5 @@
 use pgt_schema_cache::PostgresType;
-use pgt_treesitter_queries::{TreeSitterQueriesExecutor, queries::ParameterMatch};
+use pgt_treesitter::queries::{ParameterMatch, TreeSitterQueriesExecutor};
 
 /// A typed identifier is a parameter that has a type associated with it.
 /// It is used to replace parameters within the SQL string.
diff --git a/crates/pgt_typecheck/tests/diagnostics.rs b/crates/pgt_typecheck/tests/diagnostics.rs
index a7448503a..f21d9ef9b 100644
--- a/crates/pgt_typecheck/tests/diagnostics.rs
+++ b/crates/pgt_typecheck/tests/diagnostics.rs
@@ -23,7 +23,10 @@ async fn test(name: &str, query: &str, setup: Option<&str>, test_db: &PgPool) {
         .await
         .expect("Failed to load Schema Cache");
 
-    let root = pgt_query_ext::parse(query).unwrap();
+    let root = pgt_query::parse(query)
+        .unwrap()
+        .into_root()
+        .expect("Failed to parse query");
     let tree = parser.parse(query, None).unwrap();
 
     let conn = &test_db;
diff --git a/crates/pgt_workspace/Cargo.toml b/crates/pgt_workspace/Cargo.toml
index 3ef4936b6..efded47c7 100644
--- a/crates/pgt_workspace/Cargo.toml
+++ b/crates/pgt_workspace/Cargo.toml
@@ -26,12 +26,15 @@ pgt_console               = { workspace = true }
 pgt_diagnostics           = { workspace = true }
 pgt_fs                    = { workspace = true, features = ["serde"] }
 pgt_lexer                 = { workspace = true }
+pgt_plpgsql_check         = { workspace = true }
+pgt_query                 = { workspace = true }
 pgt_query_ext             = { workspace = true }
 pgt_schema_cache          = { workspace = true }
 pgt_statement_splitter    = { workspace = true }
 pgt_suppressions          = { workspace = true }
 pgt_text_size.workspace   = true
 pgt_typecheck             = { workspace = true }
+pgt_workspace_macros      = { workspace = true }
 rustc-hash                = { workspace = true }
 schemars                  = { workspace = true, optional = true }
 serde                     = { workspace = true, features = ["derive"] }
diff --git a/crates/pgt_workspace/src/features/code_actions.rs b/crates/pgt_workspace/src/features/code_actions.rs
index 22223dd3c..cd1706d30 100644
--- a/crates/pgt_workspace/src/features/code_actions.rs
+++ b/crates/pgt_workspace/src/features/code_actions.rs
@@ -12,7 +12,7 @@ pub struct CodeActionsParams {
     pub skip: Vec<RuleSelector>,
 }
 
-#[derive(Debug, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Default)]
 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
 pub struct CodeActionsResult {
     pub actions: Vec<CodeAction>,
@@ -57,7 +57,7 @@ pub struct ExecuteStatementParams {
     pub path: PgTPath,
 }
 
-#[derive(Debug, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Default, PartialEq, Eq)]
 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
 pub struct ExecuteStatementResult {
     pub message: String,
diff --git a/crates/pgt_workspace/src/features/completions.rs b/crates/pgt_workspace/src/features/completions.rs
index c6f05c6e2..a41dd06eb 100644
--- a/crates/pgt_workspace/src/features/completions.rs
+++ b/crates/pgt_workspace/src/features/completions.rs
@@ -82,17 +82,17 @@ mod tests {
 
     use super::get_statement_for_completions;
 
-    static CURSOR_POSITION: &str = "€";
+    use pgt_test_utils::QueryWithCursorPosition;
 
     fn get_doc_and_pos(sql: &str) -> (Document, TextSize) {
         let pos = sql
-            .find(CURSOR_POSITION)
+            .find(QueryWithCursorPosition::cursor_marker())
             .expect("Please add cursor position to test sql");
 
         let pos: u32 = pos.try_into().unwrap();
 
         (
-            Document::new(sql.replace(CURSOR_POSITION, ""), 5),
+            Document::new(sql.replace(QueryWithCursorPosition::cursor_marker(), ""), 5),
             TextSize::new(pos),
         )
     }
@@ -107,7 +107,7 @@ mod tests {
 
             select 1;
         "#,
-            CURSOR_POSITION
+            QueryWithCursorPosition::cursor_marker()
         );
 
         let (doc, position) = get_doc_and_pos(sql.as_str());
@@ -120,7 +120,7 @@ mod tests {
 
     #[test]
     fn does_not_break_when_no_statements_exist() {
-        let sql = CURSOR_POSITION.to_string();
+        let sql = QueryWithCursorPosition::cursor_marker().to_string();
 
         let (doc, position) = get_doc_and_pos(sql.as_str());
 
@@ -129,7 +129,10 @@ mod tests {
 
     #[test]
     fn does_not_return_overlapping_statements_if_too_close() {
-        let sql = format!("select * from {}select 1;", CURSOR_POSITION);
+        let sql = format!(
+            "select * from {}select 1;",
+            QueryWithCursorPosition::cursor_marker()
+        );
 
         let (doc, position) = get_doc_and_pos(sql.as_str());
 
@@ -141,7 +144,10 @@ mod tests {
 
     #[test]
     fn is_fine_with_spaces() {
-        let sql = format!("select * from     {}     ;", CURSOR_POSITION);
+        let sql = format!(
+            "select * from     {}     ;",
+            QueryWithCursorPosition::cursor_marker()
+        );
 
         let (doc, position) = get_doc_and_pos(sql.as_str());
 
@@ -153,7 +159,7 @@ mod tests {
 
     #[test]
     fn considers_offset() {
-        let sql = format!("select * from {}", CURSOR_POSITION);
+        let sql = format!("select * from {}", QueryWithCursorPosition::cursor_marker());
 
         let (doc, position) = get_doc_and_pos(sql.as_str());
 
@@ -174,7 +180,7 @@ mod tests {
                 select {} from cool;
             $$;
         "#,
-            CURSOR_POSITION
+            QueryWithCursorPosition::cursor_marker()
         );
 
         let sql = sql.trim();
@@ -189,7 +195,10 @@ mod tests {
 
     #[test]
     fn does_not_consider_too_far_offset() {
-        let sql = format!("select * from  {}", CURSOR_POSITION);
+        let sql = format!(
+            "select * from  {}",
+            QueryWithCursorPosition::cursor_marker()
+        );
 
         let (doc, position) = get_doc_and_pos(sql.as_str());
 
@@ -198,7 +207,10 @@ mod tests {
 
     #[test]
     fn does_not_consider_offset_if_statement_terminated_by_semi() {
-        let sql = format!("select * from users;{}", CURSOR_POSITION);
+        let sql = format!(
+            "select * from users;{}",
+            QueryWithCursorPosition::cursor_marker()
+        );
 
         let (doc, position) = get_doc_and_pos(sql.as_str());
 
diff --git a/crates/pgt_workspace/src/features/diagnostics.rs b/crates/pgt_workspace/src/features/diagnostics.rs
index ff60e142c..a697641ed 100644
--- a/crates/pgt_workspace/src/features/diagnostics.rs
+++ b/crates/pgt_workspace/src/features/diagnostics.rs
@@ -12,7 +12,7 @@ pub struct PullDiagnosticsParams {
     pub skip: Vec<RuleSelector>,
 }
 
-#[derive(Debug, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Default)]
 #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
 pub struct PullDiagnosticsResult {
     pub diagnostics: Vec<pgt_diagnostics::serde::Diagnostic>,
diff --git a/crates/pgt_workspace/src/workspace/server.rs b/crates/pgt_workspace/src/workspace/server.rs
index e6456afc7..f4a9561f2 100644
--- a/crates/pgt_workspace/src/workspace/server.rs
+++ b/crates/pgt_workspace/src/workspace/server.rs
@@ -21,6 +21,7 @@ use pgt_diagnostics::{
 };
 use pgt_fs::{ConfigName, PgTPath};
 use pgt_typecheck::{IdentifierType, TypecheckParams, TypedIdentifier};
+use pgt_workspace_macros::ignored_path;
 use schema_cache_manager::SchemaCacheManager;
 use sqlx::{Executor, PgPool};
 use tracing::{debug, info};
@@ -30,7 +31,7 @@ use crate::{
     configuration::to_analyser_rules,
     features::{
         code_actions::{
-            self, CodeAction, CodeActionKind, CodeActionsResult, CommandAction,
+            CodeAction, CodeActionKind, CodeActionsParams, CodeActionsResult, CommandAction,
             CommandActionCategory, ExecuteStatementParams, ExecuteStatementResult,
         },
         completions::{CompletionsResult, GetCompletionsParams, get_statement_for_completions},
@@ -54,7 +55,6 @@ mod async_helper;
 mod connection_key;
 mod connection_manager;
 pub(crate) mod document;
-mod function_utils;
 mod migration;
 mod pg_query;
 mod schema_cache_manager;
@@ -262,6 +262,7 @@ impl Workspace for WorkspaceServer {
     }
 
     /// Add a new file to the workspace
+    #[ignored_path(path=&params.path)]
     #[tracing::instrument(level = "info", skip_all, fields(path = params.path.as_path().as_os_str().to_str()), err)]
     fn open_file(&self, params: OpenFileParams) -> Result<(), WorkspaceError> {
         let mut documents = self.documents.write().unwrap();
@@ -277,6 +278,7 @@ impl Workspace for WorkspaceServer {
     }
 
     /// Remove a file from the workspace
+    #[ignored_path(path=&params.path)]
     fn close_file(&self, params: super::CloseFileParams) -> Result<(), WorkspaceError> {
         let mut documents = self.documents.write().unwrap();
         documents
@@ -291,6 +293,7 @@ impl Workspace for WorkspaceServer {
         path = params.path.as_os_str().to_str(),
         version = params.version
     ), err)]
+    #[ignored_path(path=&params.path)]
     fn change_file(&self, params: super::ChangeFileParams) -> Result<(), WorkspaceError> {
         let mut documents = self.documents.write().unwrap();
 
@@ -312,6 +315,7 @@ impl Workspace for WorkspaceServer {
         None
     }
 
+    #[ignored_path(path=&params.path)]
     fn get_file_content(&self, params: GetFileContentParams) -> Result<String, WorkspaceError> {
         let documents = self.documents.read().unwrap();
         let document = documents
@@ -324,10 +328,11 @@ impl Workspace for WorkspaceServer {
         Ok(self.is_ignored(params.pgt_path.as_path()))
     }
 
+    #[ignored_path(path=&params.path)]
     fn pull_code_actions(
         &self,
-        params: code_actions::CodeActionsParams,
-    ) -> Result<code_actions::CodeActionsResult, WorkspaceError> {
+        params: CodeActionsParams,
+    ) -> Result<CodeActionsResult, WorkspaceError> {
         let documents = self.documents.read().unwrap();
         let parser = documents
             .get(&params.path)
@@ -366,6 +371,7 @@ impl Workspace for WorkspaceServer {
         Ok(CodeActionsResult { actions })
     }
 
+    #[ignored_path(path=&params.path)]
     fn execute_statement(
         &self,
         params: ExecuteStatementParams,
@@ -409,6 +415,7 @@ impl Workspace for WorkspaceServer {
         })
     }
 
+    #[ignored_path(path=&params.path)]
     fn pull_diagnostics(
         &self,
         params: PullDiagnosticsParams,
@@ -446,7 +453,8 @@ impl Workspace for WorkspaceServer {
             let path_clone = params.path.clone();
             let schema_cache = self.schema_cache.load(pool.clone())?;
             let input = doc.iter(TypecheckDiagnosticsMapper).collect::<Vec<_>>();
-            // sorry for the ugly code :(
+
+            // Combined async context for both typecheck and plpgsql_check
             let async_results = run_async(async move {
                 stream::iter(input)
                     .map(|(id, range, ast, cst, sign)| {
@@ -454,8 +462,11 @@ impl Workspace for WorkspaceServer {
                         let path = path_clone.clone();
                         let schema_cache = Arc::clone(&schema_cache);
                         async move {
+                            let mut diagnostics = Vec::new();
+
                             if let Some(ast) = ast {
-                                pgt_typecheck::check_sql(TypecheckParams {
+                                // Type checking
+                                let typecheck_result = pgt_typecheck::check_sql(TypecheckParams {
                                     conn: &pool,
                                     sql: id.content(),
                                     ast: &ast,
@@ -478,18 +489,40 @@ impl Workspace for WorkspaceServer {
                                         })
                                         .unwrap_or_default(),
                                 })
+                                .await;
+
+                                if let Ok(Some(diag)) = typecheck_result {
+                                    let r = diag.location().span.map(|span| span + range.start());
+                                    diagnostics.push(
+                                        diag.with_file_path(path.as_path().display().to_string())
+                                            .with_file_span(r.unwrap_or(range)),
+                                    );
+                                }
+
+                                // plpgsql_check
+                                let plpgsql_check_results = pgt_plpgsql_check::check_plpgsql(
+                                    pgt_plpgsql_check::PlPgSqlCheckParams {
+                                        conn: &pool,
+                                        sql: id.content(),
+                                        ast: &ast,
+                                        schema_cache: schema_cache.as_ref(),
+                                    },
+                                )
                                 .await
-                                .map(|d| {
-                                    d.map(|d| {
-                                        let r = d.location().span.map(|span| span + range.start());
+                                .unwrap_or_else(|_| vec![]);
 
+                                println!("{:#?}", plpgsql_check_results);
+
+                                for d in plpgsql_check_results {
+                                    let r = d.span.map(|span| span + range.start());
+                                    diagnostics.push(
                                         d.with_file_path(path.as_path().display().to_string())
-                                            .with_file_span(r.unwrap_or(range))
-                                    })
-                                })
-                            } else {
-                                Ok(None)
+                                            .with_file_span(r.unwrap_or(range)),
+                                    );
+                                }
                             }
+
+                            Ok::<Vec<pgt_diagnostics::Error>, sqlx::Error>(diagnostics)
                         }
                     })
                     .buffer_unordered(10)
@@ -498,8 +531,8 @@ impl Workspace for WorkspaceServer {
             })?;
 
             for result in async_results.into_iter() {
-                let result = result?;
-                if let Some(diag) = result {
+                let diagnostics_batch = result?;
+                for diag in diagnostics_batch {
                     diagnostics.push(SDiagnostic::new(diag));
                 }
             }
@@ -540,6 +573,20 @@ impl Workspace for WorkspaceServer {
                 analysable_stmts.push(node);
             }
             if let Some(diag) = diagnostic {
+                // ignore the syntax error if we already have more specialized diagnostics for the
+                // same statement.
+                // this is important for create function statements, where we might already have detailed
+                // diagnostics from plpgsql_check.
+                if diagnostics.iter().any(|d| {
+                    d.location().span.is_some_and(|async_loc| {
+                        diag.location()
+                            .span
+                            .is_some_and(|syntax_loc| syntax_loc.contains_range(async_loc))
+                    })
+                }) {
+                    continue;
+                }
+
                 diagnostics.push(SDiagnostic::new(
                     diag.with_file_path(path.clone())
                         .with_severity(Severity::Error),
@@ -607,6 +654,7 @@ impl Workspace for WorkspaceServer {
         })
     }
 
+    #[ignored_path(path=&params.path)]
     #[tracing::instrument(level = "debug", skip_all, fields(
         path = params.path.as_os_str().to_str(),
         position = params.position.to_string()
diff --git a/crates/pgt_workspace/src/workspace/server.tests.rs b/crates/pgt_workspace/src/workspace/server.tests.rs
index c3fbf7239..ef5ba2677 100644
--- a/crates/pgt_workspace/src/workspace/server.tests.rs
+++ b/crates/pgt_workspace/src/workspace/server.tests.rs
@@ -1,15 +1,21 @@
-use biome_deserialize::Merge;
+use std::sync::Arc;
+
+use biome_deserialize::{Merge, StringSet};
 use pgt_analyse::RuleCategories;
-use pgt_configuration::{PartialConfiguration, database::PartialDatabaseConfiguration};
+use pgt_configuration::{
+    PartialConfiguration, database::PartialDatabaseConfiguration, files::PartialFilesConfiguration,
+};
 use pgt_diagnostics::Diagnostic;
 use pgt_fs::PgTPath;
 use pgt_text_size::TextRange;
-use sqlx::PgPool;
+use sqlx::{Executor, PgPool};
 
 use crate::{
     Workspace, WorkspaceError,
+    features::code_actions::ExecuteStatementResult,
     workspace::{
-        OpenFileParams, RegisterProjectFolderParams, UpdateSettingsParams, server::WorkspaceServer,
+        OpenFileParams, RegisterProjectFolderParams, StatementId, UpdateSettingsParams,
+        server::WorkspaceServer,
     },
 };
 
@@ -152,3 +158,122 @@ async fn test_syntax_error(test_db: PgPool) {
         Some(TextRange::new(7.into(), 15.into()))
     );
 }
+
+#[tokio::test]
+async fn correctly_ignores_files() {
+    let mut conf = PartialConfiguration::init();
+    conf.merge_with(PartialConfiguration {
+        files: Some(PartialFilesConfiguration {
+            ignore: Some(StringSet::from_iter(["test.sql".to_string()])),
+            ..Default::default()
+        }),
+        ..Default::default()
+    });
+
+    let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace");
+
+    let path = PgTPath::new("test.sql");
+    let content = r#"
+      seect 1;
+    "#;
+
+    let diagnostics_result = workspace.pull_diagnostics(crate::workspace::PullDiagnosticsParams {
+        path: path.clone(),
+        categories: RuleCategories::all(),
+        max_diagnostics: 100,
+        only: vec![],
+        skip: vec![],
+    });
+
+    assert!(
+        diagnostics_result.is_ok_and(|res| res.diagnostics.is_empty()
+            && res.errors == 0
+            && res.skipped_diagnostics == 0)
+    );
+
+    let close_file_result =
+        workspace.close_file(crate::workspace::CloseFileParams { path: path.clone() });
+
+    assert!(close_file_result.is_ok());
+
+    let execute_statement_result =
+        workspace.execute_statement(crate::workspace::ExecuteStatementParams {
+            path: path.clone(),
+            statement_id: StatementId::Root {
+                content: Arc::from(content),
+            },
+        });
+
+    assert!(execute_statement_result.is_ok_and(|res| res == ExecuteStatementResult::default()));
+}
+
+#[cfg(all(test, not(target_os = "windows")))]
+#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")]
+async fn test_dedupe_diagnostics(test_db: PgPool) {
+    let mut conf = PartialConfiguration::init();
+    conf.merge_with(PartialConfiguration {
+        db: Some(PartialDatabaseConfiguration {
+            database: Some(
+                test_db
+                    .connect_options()
+                    .get_database()
+                    .unwrap()
+                    .to_string(),
+            ),
+            ..Default::default()
+        }),
+        ..Default::default()
+    });
+
+    let workspace = get_test_workspace(Some(conf)).expect("Unable to create test workspace");
+
+    let path = PgTPath::new("test.sql");
+
+    let setup_sql = "CREATE EXTENSION IF NOT EXISTS plpgsql_check;";
+    test_db.execute(setup_sql).await.expect("setup sql failed");
+
+    let content = r#"
+        CREATE OR REPLACE FUNCTION public.f1()
+        RETURNS void
+        LANGUAGE plpgsql
+        AS $function$
+        decare r text;
+        BEGIN
+            select '1' into into r;
+        END;
+        $function$;
+    "#;
+
+    workspace
+        .open_file(OpenFileParams {
+            path: path.clone(),
+            content: content.into(),
+            version: 1,
+        })
+        .expect("Unable to open test file");
+
+    let diagnostics = workspace
+        .pull_diagnostics(crate::workspace::PullDiagnosticsParams {
+            path: path.clone(),
+            categories: RuleCategories::all(),
+            max_diagnostics: 100,
+            only: vec![],
+            skip: vec![],
+        })
+        .expect("Unable to pull diagnostics")
+        .diagnostics;
+
+    assert_eq!(diagnostics.len(), 1, "Expected one diagnostic");
+
+    let diagnostic = &diagnostics[0];
+
+    assert_eq!(
+        diagnostic.category().map(|c| c.name()),
+        Some("plpgsql_check")
+    );
+
+    assert_eq!(
+        diagnostic.location().span,
+        Some(TextRange::new(115.into(), 210.into()))
+    );
+}
diff --git a/crates/pgt_workspace/src/workspace/server/document.rs b/crates/pgt_workspace/src/workspace/server/document.rs
index c9f880eca..c8cdc1f1d 100644
--- a/crates/pgt_workspace/src/workspace/server/document.rs
+++ b/crates/pgt_workspace/src/workspace/server/document.rs
@@ -191,12 +191,7 @@ impl<'a> StatementMapper<'a> for DefaultMapper {
 
 pub struct ExecuteStatementMapper;
 impl<'a> StatementMapper<'a> for ExecuteStatementMapper {
-    type Output = (
-        StatementId,
-        TextRange,
-        String,
-        Option<pgt_query_ext::NodeEnum>,
-    );
+    type Output = (StatementId, TextRange, String, Option<pgt_query::NodeEnum>);
 
     fn map(&self, parser: &'a Document, id: StatementId, range: TextRange) -> Self::Output {
         let ast_result = parser.ast_db.get_or_cache_ast(&id);
@@ -214,7 +209,7 @@ impl<'a> StatementMapper<'a> for TypecheckDiagnosticsMapper {
     type Output = (
         StatementId,
         TextRange,
-        Option<pgt_query_ext::NodeEnum>,
+        Option<pgt_query::NodeEnum>,
         Arc<tree_sitter::Tree>,
         Option<SQLFunctionSignature>,
     );
diff --git a/crates/pgt_workspace/src/workspace/server/function_utils.rs b/crates/pgt_workspace/src/workspace/server/function_utils.rs
deleted file mode 100644
index cf02ceb19..000000000
--- a/crates/pgt_workspace/src/workspace/server/function_utils.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-/// Helper function to find a specific option value from function options
-pub fn find_option_value(
-    create_fn: &pgt_query_ext::protobuf::CreateFunctionStmt,
-    option_name: &str,
-) -> Option<String> {
-    create_fn
-        .options
-        .iter()
-        .filter_map(|opt_wrapper| opt_wrapper.node.as_ref())
-        .find_map(|opt| {
-            if let pgt_query_ext::NodeEnum::DefElem(def_elem) = opt {
-                if def_elem.defname == option_name {
-                    def_elem
-                        .arg
-                        .iter()
-                        .filter_map(|arg_wrapper| arg_wrapper.node.as_ref())
-                        .find_map(|arg| {
-                            if let pgt_query_ext::NodeEnum::String(s) = arg {
-                                Some(s.sval.clone())
-                            } else if let pgt_query_ext::NodeEnum::List(l) = arg {
-                                l.items.iter().find_map(|item_wrapper| {
-                                    if let Some(pgt_query_ext::NodeEnum::String(s)) =
-                                        item_wrapper.node.as_ref()
-                                    {
-                                        Some(s.sval.clone())
-                                    } else {
-                                        None
-                                    }
-                                })
-                            } else {
-                                None
-                            }
-                        })
-                } else {
-                    None
-                }
-            } else {
-                None
-            }
-        })
-}
-
-pub fn parse_name(nodes: &[pgt_query_ext::protobuf::Node]) -> Option<(Option<String>, String)> {
-    let names = nodes
-        .iter()
-        .map(|n| match &n.node {
-            Some(pgt_query_ext::NodeEnum::String(s)) => Some(s.sval.clone()),
-            _ => None,
-        })
-        .collect::<Vec<_>>();
-
-    match names.as_slice() {
-        [Some(schema), Some(name)] => Some((Some(schema.clone()), name.clone())),
-        [Some(name)] => Some((None, name.clone())),
-        _ => None,
-    }
-}
diff --git a/crates/pgt_workspace/src/workspace/server/pg_query.rs b/crates/pgt_workspace/src/workspace/server/pg_query.rs
index ba471dfa5..05f1425dc 100644
--- a/crates/pgt_workspace/src/workspace/server/pg_query.rs
+++ b/crates/pgt_workspace/src/workspace/server/pg_query.rs
@@ -5,13 +5,12 @@ use lru::LruCache;
 use pgt_query_ext::diagnostics::*;
 use pgt_text_size::TextRange;
 
-use super::function_utils::find_option_value;
 use super::statement_identifier::StatementId;
 
 const DEFAULT_CACHE_SIZE: usize = 1000;
 
 pub struct PgQueryStore {
-    ast_db: Mutex<LruCache<StatementId, Arc<Result<pgt_query_ext::NodeEnum, SyntaxDiagnostic>>>>,
+    ast_db: Mutex<LruCache<StatementId, Arc<Result<pgt_query::NodeEnum, SyntaxDiagnostic>>>>,
     plpgsql_db: Mutex<LruCache<StatementId, Result<(), SyntaxDiagnostic>>>,
 }
 
@@ -30,14 +29,22 @@ impl PgQueryStore {
     pub fn get_or_cache_ast(
         &self,
         statement: &StatementId,
-    ) -> Arc<Result<pgt_query_ext::NodeEnum, SyntaxDiagnostic>> {
+    ) -> Arc<Result<pgt_query::NodeEnum, SyntaxDiagnostic>> {
         let mut cache = self.ast_db.lock().unwrap();
 
         if let Some(existing) = cache.get(statement) {
             return existing.clone();
         }
 
-        let r = Arc::new(pgt_query_ext::parse(statement.content()).map_err(SyntaxDiagnostic::from));
+        let r = Arc::new(
+            pgt_query::parse(statement.content())
+                .map_err(SyntaxDiagnostic::from)
+                .and_then(|ast| {
+                    ast.into_root().ok_or_else(|| {
+                        SyntaxDiagnostic::new("No root node found in parse result", None)
+                    })
+                }),
+        );
         cache.put(statement.clone(), r.clone());
         r
     }
@@ -49,11 +56,11 @@ impl PgQueryStore {
         let ast = self.get_or_cache_ast(statement);
 
         let create_fn = match ast.as_ref() {
-            Ok(pgt_query_ext::NodeEnum::CreateFunctionStmt(node)) => node,
+            Ok(pgt_query::NodeEnum::CreateFunctionStmt(node)) => node,
             _ => return None,
         };
 
-        let language = find_option_value(create_fn, "language")?;
+        let language = pgt_query_ext::utils::find_option_value(create_fn, "language")?;
 
         if language != "plpgsql" {
             return None;
@@ -65,14 +72,14 @@ impl PgQueryStore {
             return Some(existing.clone());
         }
 
-        let sql_body = find_option_value(create_fn, "as")?;
+        let sql_body = pgt_query_ext::utils::find_option_value(create_fn, "as")?;
 
         let start = statement.content().find(&sql_body)?;
         let end = start + sql_body.len();
 
         let range = TextRange::new(start.try_into().unwrap(), end.try_into().unwrap());
 
-        let r = pgt_query_ext::parse_plpgsql(statement.content())
+        let r = pgt_query::parse_plpgsql(statement.content())
             .map_err(|err| SyntaxDiagnostic::new(err.to_string(), Some(range)));
         cache.put(statement.clone(), r.clone());
 
diff --git a/crates/pgt_workspace/src/workspace/server/sql_function.rs b/crates/pgt_workspace/src/workspace/server/sql_function.rs
index 6161dda78..4a1463b71 100644
--- a/crates/pgt_workspace/src/workspace/server/sql_function.rs
+++ b/crates/pgt_workspace/src/workspace/server/sql_function.rs
@@ -1,7 +1,5 @@
 use pgt_text_size::TextRange;
 
-use super::function_utils::{find_option_value, parse_name};
-
 #[derive(Debug, Clone)]
 pub struct ArgType {
     pub schema: Option<String>,
@@ -30,30 +28,30 @@ pub struct SQLFunctionBody {
 }
 
 /// Extracts the function signature from a SQL function definition
-pub fn get_sql_fn_signature(ast: &pgt_query_ext::NodeEnum) -> Option<SQLFunctionSignature> {
+pub fn get_sql_fn_signature(ast: &pgt_query::NodeEnum) -> Option<SQLFunctionSignature> {
     let create_fn = match ast {
-        pgt_query_ext::NodeEnum::CreateFunctionStmt(cf) => cf,
+        pgt_query::NodeEnum::CreateFunctionStmt(cf) => cf,
         _ => return None,
     };
 
     // Extract language from function options
-    let language = find_option_value(create_fn, "language")?;
+    let language = pgt_query_ext::utils::find_option_value(create_fn, "language")?;
 
     // Only process SQL functions
     if language != "sql" {
         return None;
     }
 
-    let fn_name = parse_name(&create_fn.funcname)?;
+    let fn_name = pgt_query_ext::utils::parse_name(&create_fn.funcname)?;
 
     // we return None if anything is not expected
     let mut fn_args = Vec::new();
     for arg in &create_fn.parameters {
-        if let Some(pgt_query_ext::NodeEnum::FunctionParameter(node)) = &arg.node {
+        if let Some(pgt_query::NodeEnum::FunctionParameter(node)) = &arg.node {
             let arg_name = (!node.name.is_empty()).then_some(node.name.clone());
 
             let arg_type = node.arg_type.as_ref()?;
-            let type_name = parse_name(&arg_type.names)?;
+            let type_name = pgt_query_ext::utils::parse_name(&arg_type.names)?;
             fn_args.push(SQLFunctionArg {
                 name: arg_name,
                 type_: ArgType {
@@ -79,14 +77,14 @@ pub fn get_sql_fn_signature(ast: &pgt_query_ext::NodeEnum) -> Option<SQLFunction
 }
 
 /// Extracts the SQL body from a function definition
-pub fn get_sql_fn_body(ast: &pgt_query_ext::NodeEnum, content: &str) -> Option<SQLFunctionBody> {
+pub fn get_sql_fn_body(ast: &pgt_query::NodeEnum, content: &str) -> Option<SQLFunctionBody> {
     let create_fn = match ast {
-        pgt_query_ext::NodeEnum::CreateFunctionStmt(cf) => cf,
+        pgt_query::NodeEnum::CreateFunctionStmt(cf) => cf,
         _ => return None,
     };
 
     // Extract language from function options
-    let language = find_option_value(create_fn, "language")?;
+    let language = pgt_query_ext::utils::find_option_value(create_fn, "language")?;
 
     // Only process SQL functions
     if language != "sql" {
@@ -94,7 +92,7 @@ pub fn get_sql_fn_body(ast: &pgt_query_ext::NodeEnum, content: &str) -> Option<S
     }
 
     // Extract SQL body from function options
-    let sql_body = find_option_value(create_fn, "as")?;
+    let sql_body = pgt_query_ext::utils::find_option_value(create_fn, "as")?;
 
     // Find the range of the SQL body in the content
     let start = content.find(&sql_body)?;
@@ -120,7 +118,7 @@ mod tests {
     IMMUTABLE
     RETURNS NULL ON NULL INPUT;";
 
-        let ast = pgt_query_ext::parse(input).unwrap();
+        let ast = pgt_query::parse(input).unwrap().into_root().unwrap();
 
         let sig = get_sql_fn_signature(&ast);
 
@@ -146,7 +144,7 @@ mod tests {
     IMMUTABLE
     RETURNS NULL ON NULL INPUT;";
 
-        let ast = pgt_query_ext::parse(input).unwrap();
+        let ast = pgt_query::parse(input).unwrap().into_root().unwrap();
 
         let sig = get_sql_fn_signature(&ast);
 
diff --git a/crates/pgt_query_proto_parser/Cargo.toml b/crates/pgt_workspace_macros/Cargo.toml
similarity index 63%
rename from crates/pgt_query_proto_parser/Cargo.toml
rename to crates/pgt_workspace_macros/Cargo.toml
index 729c94b42..c192db04b 100644
--- a/crates/pgt_query_proto_parser/Cargo.toml
+++ b/crates/pgt_workspace_macros/Cargo.toml
@@ -6,15 +6,14 @@ edition.workspace    = true
 homepage.workspace   = true
 keywords.workspace   = true
 license.workspace    = true
-name                 = "pgt_query_proto_parser"
+name                 = "pgt_workspace_macros"
 repository.workspace = true
 version              = "0.0.0"
 
+[lib]
+proc-macro = true
 
 [dependencies]
-convert_case   = "0.6.0"
-protobuf       = "3.3.0"
-protobuf-parse = "3.3.0"
-
-[lib]
-doctest = false
+proc-macro2 = { version = "1.0.95" }
+quote       = { workspace = true }
+syn         = { workspace = true }
diff --git a/crates/pgt_workspace_macros/src/lib.rs b/crates/pgt_workspace_macros/src/lib.rs
new file mode 100644
index 000000000..d46f484da
--- /dev/null
+++ b/crates/pgt_workspace_macros/src/lib.rs
@@ -0,0 +1,123 @@
+use std::ops::Deref;
+
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{TypePath, TypeTuple, parse_macro_input};
+
+struct IgnoredPath {
+    path: syn::Expr,
+}
+
+impl syn::parse::Parse for IgnoredPath {
+    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+        let arg_name: syn::Ident = input.parse()?;
+
+        if arg_name != "path" {
+            return Err(syn::Error::new_spanned(
+                arg_name,
+                "Expected 'path' argument.",
+            ));
+        }
+
+        let _: syn::Token!(=) = input.parse()?;
+        let path: syn::Expr = input.parse()?;
+
+        Ok(Self { path })
+    }
+}
+
+#[proc_macro_attribute]
+/// You can use this on a workspace server function to return a default if the specified path
+/// is ignored by the user's settings.
+///
+/// This will work for any function where &self is in scope and that returns `Result<T, E>`, `Result<(), E>`, or `T`, where `T: Default`.
+/// `path` needs to point at a `&PgTPath`.
+///
+/// ### Usage
+///
+/// ```ignore
+/// impl WorkspaceServer {
+///   #[ignore_path(path=&params.path)]
+///   fn foo(&self, params: FooParams) -> Result<FooResult, WorkspaceError> {
+///     ... codeblock
+///   }
+/// }
+///
+/// // …expands to…
+///
+/// impl WorkspaceServer {
+///   fn foo(&self, params: FooParams) -> Result<FooResult, WorkspaceError> {
+///     if self.is_ignored(&params.path) {
+///       return Ok(FooResult::default());
+///     }
+///     ... codeblock
+///   }
+/// }
+/// ```
+pub fn ignored_path(args: TokenStream, input: TokenStream) -> TokenStream {
+    let ignored_path = parse_macro_input!(args as IgnoredPath);
+    let input_fn = parse_macro_input!(input as syn::ItemFn);
+
+    let macro_specified_path = ignored_path.path;
+
+    let vis = &input_fn.vis;
+    let sig = &input_fn.sig;
+    let block = &input_fn.block;
+    let attrs = &input_fn.attrs;
+
+    // handles cases `fn foo() -> Result<T, E>` and `fn foo() -> Result<(), E>`
+    // T needs to implement default
+    if let syn::ReturnType::Type(_, ty) = &sig.output {
+        if let syn::Type::Path(TypePath { path, .. }) = ty.deref() {
+            if let Some(seg) = path.segments.last() {
+                if seg.ident == "Result" {
+                    if let syn::PathArguments::AngleBracketed(type_args) = &seg.arguments {
+                        if let Some(syn::GenericArgument::Type(t)) = type_args.args.first() {
+                            if let syn::Type::Tuple(TypeTuple { elems, .. }) = t {
+                                // case: Result<(), E>
+                                if elems.is_empty() {
+                                    return TokenStream::from(quote! {
+                                      #(#attrs)*
+                                      #vis #sig {
+                                        if self.is_ignored(#macro_specified_path) {
+                                          return Ok(());
+                                        };
+                                        #block
+                                      }
+                                    });
+                                }
+                            }
+                            if let syn::Type::Path(TypePath { path, .. }) = t {
+                                if let Some(seg) = path.segments.first() {
+                                    let ident = &seg.ident;
+                                    return TokenStream::from(quote! {
+                                      #(#attrs)*
+                                      #vis #sig {
+                                        if self.is_ignored(#macro_specified_path) {
+                                          return Ok(#ident::default());
+                                        };
+                                        #block
+                                      }
+                                    });
+                                }
+                            }
+                        };
+                    };
+                };
+            };
+        };
+    };
+
+    // case fn foo() -> T {}
+    // handles all other T's
+    // T needs to implement Default
+    TokenStream::from(quote! {
+      #(#attrs)*
+      #vis #sig {
+        if self.is_ignored(#macro_specified_path) {
+          return Default::default();
+        }
+        #block
+      }
+    })
+}
diff --git a/docker-compose.yml b/docker-compose.yml
index fede1d664..468d4cc30 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,7 +1,7 @@
 services:
   db:
     # postgres://postgres:postgres@127.0.0.1:5432/postgres
-    image: postgres
+    build: .
     restart: always
     environment:
       - POSTGRES_USER=postgres
diff --git a/docs/codegen/Cargo.toml b/docs/codegen/Cargo.toml
index 96092a7a3..bf650ac9b 100644
--- a/docs/codegen/Cargo.toml
+++ b/docs/codegen/Cargo.toml
@@ -26,6 +26,7 @@ pgt_cli = { workspace = true }
 pgt_analyse = { workspace = true }
 pgt_analyser = { workspace = true }
 pgt_diagnostics = { workspace = true }
+pgt_query = { workspace = true }
 pgt_query_ext = { workspace = true }
 pgt_workspace = { workspace = true }
 pgt_statement_splitter = { workspace = true }
diff --git a/docs/codegen/src/rules_docs.rs b/docs/codegen/src/rules_docs.rs
index 1d4b86a9e..67626237d 100644
--- a/docs/codegen/src/rules_docs.rs
+++ b/docs/codegen/src/rules_docs.rs
@@ -444,28 +444,30 @@ fn print_diagnostics(
     // split and parse each statement
     let stmts = pgt_statement_splitter::split(code);
     for stmt_range in stmts.ranges {
-        match pgt_query_ext::parse(&code[stmt_range]) {
+        match pgt_query::parse(&code[stmt_range]) {
             Ok(ast) => {
-                for rule_diag in analyser.run(pgt_analyser::AnalyserParams {
-                    schema_cache: None,
-                    stmts: vec![AnalysableStatement {
-                        range: stmt_range,
-                        root: ast,
-                    }],
-                }) {
-                    let diag = pgt_diagnostics::serde::Diagnostic::new(rule_diag);
-
-                    let category = diag.category().expect("linter diagnostic has no code");
-                    let severity = settings.get_severity_from_rule_code(category).expect(
+                if let Some(root) = ast.into_root() {
+                    for rule_diag in analyser.run(pgt_analyser::AnalyserParams {
+                        schema_cache: None,
+                        stmts: vec![AnalysableStatement {
+                            range: stmt_range,
+                            root,
+                        }],
+                    }) {
+                        let diag = pgt_diagnostics::serde::Diagnostic::new(rule_diag);
+
+                        let category = diag.category().expect("linter diagnostic has no code");
+                        let severity = settings.get_severity_from_rule_code(category).expect(
                                 "If you see this error, it means you need to run cargo codegen-configuration",
                             );
 
-                    let error = diag
-                        .with_severity(severity)
-                        .with_file_path(&file_path)
-                        .with_file_source_code(code);
+                        let error = diag
+                            .with_severity(severity)
+                            .with_file_path(&file_path)
+                            .with_file_source_code(code);
 
-                    write_diagnostic(code, error)?;
+                        write_diagnostic(code, error)?;
+                    }
                 }
             }
             Err(e) => {
diff --git a/docs/codegen/src/rules_index.rs b/docs/codegen/src/rules_index.rs
index 655e4bdb2..99d22580e 100644
--- a/docs/codegen/src/rules_index.rs
+++ b/docs/codegen/src/rules_index.rs
@@ -69,7 +69,7 @@ fn generate_group(
 
         write!(
             content,
-            "| [{rule_name}](/rules/{dashed_rule}) | {summary} | {properties} |"
+            "| [{rule_name}](./{dashed_rule}) | {summary} | {properties} |"
         )?;
 
         writeln!(content)?;
diff --git a/docs/codegen/src/rules_sources.rs b/docs/codegen/src/rules_sources.rs
index b8fac23d8..5b21ea933 100644
--- a/docs/codegen/src/rules_sources.rs
+++ b/docs/codegen/src/rules_sources.rs
@@ -48,12 +48,12 @@ pub fn generate_rule_sources(docs_dir: &Path) -> anyhow::Result<()> {
     for (rule_name, metadata) in rules {
         let kebab_rule_name = Case::Kebab.convert(rule_name);
         if metadata.sources.is_empty() {
-            exclusive_rules.insert((rule_name.to_string(), format!("./rules/{kebab_rule_name}")));
+            exclusive_rules.insert((rule_name.to_string(), format!("../rules/{kebab_rule_name}")));
         } else {
             for source in metadata.sources {
                 let source_set = SourceSet {
                     rule_name: rule_name.to_string(),
-                    link: format!("./rules/{kebab_rule_name}"),
+                    link: format!("../rules/{kebab_rule_name}"),
                     source_link: source.to_rule_url(),
                     source_rule_name: source.as_rule_name().to_string(),
                 };
diff --git a/docs/rule_sources.md b/docs/rule_sources.md
index 8c0f085d4..679448cdc 100644
--- a/docs/rule_sources.md
+++ b/docs/rule_sources.md
@@ -3,9 +3,9 @@
 ### Squawk
 | Squawk Rule Name | Rule Name |
 | ---- | ---- |
-| [adding-required-field](https://squawkhq.com/docs/adding-required-field) |[addingRequiredField](./rules/adding-required-field) |
-| [ban-drop-column](https://squawkhq.com/docs/ban-drop-column) |[banDropColumn](./rules/ban-drop-column) |
-| [ban-drop-database](https://squawkhq.com/docs/ban-drop-database) |[banDropDatabase](./rules/ban-drop-database) |
-| [ban-drop-not-null](https://squawkhq.com/docs/ban-drop-not-null) |[banDropNotNull](./rules/ban-drop-not-null) |
-| [ban-drop-table](https://squawkhq.com/docs/ban-drop-table) |[banDropTable](./rules/ban-drop-table) |
-| [ban-truncate-cascade](https://squawkhq.com/docs/ban-truncate-cascade) |[banTruncateCascade](./rules/ban-truncate-cascade) |
+| [adding-required-field](https://squawkhq.com/docs/adding-required-field) |[addingRequiredField](../rules/adding-required-field) |
+| [ban-drop-column](https://squawkhq.com/docs/ban-drop-column) |[banDropColumn](../rules/ban-drop-column) |
+| [ban-drop-database](https://squawkhq.com/docs/ban-drop-database) |[banDropDatabase](../rules/ban-drop-database) |
+| [ban-drop-not-null](https://squawkhq.com/docs/ban-drop-not-null) |[banDropNotNull](../rules/ban-drop-not-null) |
+| [ban-drop-table](https://squawkhq.com/docs/ban-drop-table) |[banDropTable](../rules/ban-drop-table) |
+| [ban-truncate-cascade](https://squawkhq.com/docs/ban-truncate-cascade) |[banTruncateCascade](../rules/ban-truncate-cascade) |
diff --git a/docs/rules.md b/docs/rules.md
index 19e110c6a..d74b67e88 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -12,12 +12,12 @@ Rules that detect potential safety issues in your code.
 
 | Rule name | Description | Properties |
 | --- | --- | --- |
-| [addingRequiredField](/rules/adding-required-field) | Adding a new column that is NOT NULL and has no default value to an existing table effectively makes it required. |  |
-| [banDropColumn](/rules/ban-drop-column) | Dropping a column may break existing clients. | ✅ |
-| [banDropDatabase](/rules/ban-drop-database) | Dropping a database may break existing clients (and everything else, really). |  |
-| [banDropNotNull](/rules/ban-drop-not-null) | Dropping a NOT NULL constraint may break existing clients. | ✅ |
-| [banDropTable](/rules/ban-drop-table) | Dropping a table may break existing clients. | ✅ |
-| [banTruncateCascade](/rules/ban-truncate-cascade) | Using `TRUNCATE`'s `CASCADE` option will truncate any tables that are also foreign-keyed to the specified tables. |  |
+| [addingRequiredField](./adding-required-field) | Adding a new column that is NOT NULL and has no default value to an existing table effectively makes it required. |  |
+| [banDropColumn](./ban-drop-column) | Dropping a column may break existing clients. | ✅ |
+| [banDropDatabase](./ban-drop-database) | Dropping a database may break existing clients (and everything else, really). |  |
+| [banDropNotNull](./ban-drop-not-null) | Dropping a NOT NULL constraint may break existing clients. | ✅ |
+| [banDropTable](./ban-drop-table) | Dropping a table may break existing clients. | ✅ |
+| [banTruncateCascade](./ban-truncate-cascade) | Using `TRUNCATE`'s `CASCADE` option will truncate any tables that are also foreign-keyed to the specified tables. |  |
 
 [//]: # (END RULES_INDEX)
 
diff --git a/libpg_query b/libpg_query
deleted file mode 160000
index 1c1a32ed2..000000000
--- a/libpg_query
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 1c1a32ed2f4c7799830d50bf4cb159222aafec48
diff --git a/test.sql b/test.sql
index 97c8e639b..b21a2e8dc 100644
--- a/test.sql
+++ b/test.sql
@@ -24,3 +24,11 @@ begin
 end
 $$;
 
+
+create function f1()
+returns void as $$
+declare b constant int;
+begin
+  call p1(10, b);
+end;
+$$ language plpgsql;
diff --git a/xtask/codegen/src/generate_new_analyser_rule.rs b/xtask/codegen/src/generate_new_analyser_rule.rs
index 343b06731..4c4bcc696 100644
--- a/xtask/codegen/src/generate_new_analyser_rule.rs
+++ b/xtask/codegen/src/generate_new_analyser_rule.rs
@@ -132,7 +132,7 @@ pub fn generate_new_analyser_rule(
         // We sort rules to reduce conflicts between contributions made in parallel.
         let rule_line = match category {
             Category::Lint => format!(
-                r#"    "lint/{group}/{rule_name_camel}": "https://pgtools.dev/linter/rules/{kebab_case_rule}","#
+                r#"    "lint/{group}/{rule_name_camel}": "https://pgtools.dev/latest/rules/{kebab_case_rule}","#
             ),
         };
         let lint_start = match category {
diff --git a/xtask/rules_check/Cargo.toml b/xtask/rules_check/Cargo.toml
index 3f0198d1c..abd02a05b 100644
--- a/xtask/rules_check/Cargo.toml
+++ b/xtask/rules_check/Cargo.toml
@@ -11,6 +11,7 @@ pgt_analyse            = { workspace = true }
 pgt_analyser           = { workspace = true }
 pgt_console            = { workspace = true }
 pgt_diagnostics        = { workspace = true }
+pgt_query              = { workspace = true }
 pgt_query_ext          = { workspace = true }
 pgt_statement_splitter = { workspace = true }
 pgt_workspace          = { workspace = true }
diff --git a/xtask/rules_check/src/lib.rs b/xtask/rules_check/src/lib.rs
index 0c57d06f0..dfdd24ba5 100644
--- a/xtask/rules_check/src/lib.rs
+++ b/xtask/rules_check/src/lib.rs
@@ -128,28 +128,30 @@ fn assert_lint(
 
     let result = pgt_statement_splitter::split(code);
     for stmt_range in result.ranges {
-        match pgt_query_ext::parse(&code[stmt_range]) {
+        match pgt_query::parse(&code[stmt_range]) {
             Ok(ast) => {
-                for rule_diag in analyser.run(pgt_analyser::AnalyserParams {
-                    schema_cache: None,
-                    stmts: vec![AnalysableStatement {
-                        range: stmt_range,
-                        root: ast,
-                    }],
-                }) {
-                    let diag = pgt_diagnostics::serde::Diagnostic::new(rule_diag);
-
-                    let category = diag.category().expect("linter diagnostic has no code");
-                    let severity = settings.get_severity_from_rule_code(category).expect(
+                if let Some(root) = ast.into_root() {
+                    for rule_diag in analyser.run(pgt_analyser::AnalyserParams {
+                        schema_cache: None,
+                        stmts: vec![AnalysableStatement {
+                            range: stmt_range,
+                            root,
+                        }],
+                    }) {
+                        let diag = pgt_diagnostics::serde::Diagnostic::new(rule_diag);
+
+                        let category = diag.category().expect("linter diagnostic has no code");
+                        let severity = settings.get_severity_from_rule_code(category).expect(
                                 "If you see this error, it means you need to run cargo codegen-configuration",
                             );
 
-                    let error = diag
-                        .with_severity(severity)
-                        .with_file_path(&file_path)
-                        .with_file_source_code(code);
+                        let error = diag
+                            .with_severity(severity)
+                            .with_file_path(&file_path)
+                            .with_file_source_code(code);
 
-                    write_diagnostic(code, error)?;
+                        write_diagnostic(code, error)?;
+                    }
                 }
             }
             Err(e) => {
