Repository: sqlc-dev/sqlc
Pull request #2668 (2023-08-28 22:57:53)

fix(codegen): use correct Go types for bit strings and cid/oid/tid/xid with pgx/v4
resolves https://github.com/sqlc-dev/sqlc/issues/2667


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a163dd023..e11ffbd03 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -55,9 +55,12 @@ jobs:
       with:
         go-version: '1.21.0'
 
-    - name: gotestsum
+    - name: install gotestsum
       run: go install gotest.tools/gotestsum@latest
 
+    - name: install sqlc-gen-test
+      run: go install github.com/sqlc-dev/sqlc-gen-test@v0.1.0
+
     - name: install ./...
       run: go install ./...
 
diff --git a/docs/guides/plugins.md b/docs/guides/plugins.md
index 8845585c8..139a068dd 100644
--- a/docs/guides/plugins.md
+++ b/docs/guides/plugins.md
@@ -15,32 +15,20 @@ top-level `plugins` map. The `options` are serialized to a string and passed on
 to the plugin itself.
 
 
-```json
-{
-  "version": "2",
-  "plugins": [
-    {
-      "name": "greeter",
-      "wasm": {
-        "url": "https://github.com/sqlc-dev/sqlc-gen-greeter/releases/download/v0.1.0/sqlc-gen-greeter.wasm",
-        "sha256": "afc486dac2068d741d7a4110146559d12a013fd0286f42a2fc7dcd802424ad07"
-      }
-    }
-  ],
-  "sql": [
-    {
-      "schema": "schema.sql",
-      "queries": "query.sql",
-      "engine": "postgresql",
-      "codegen": [
-        {
-          "out": "gen",
-          "plugin": "greeter"
-        }
-      ]
-    }
-  ]
-}
+```yaml
+version: '2'
+plugins:
+- name: greeter
+  wasm:
+    url: https://github.com/sqlc-dev/sqlc-gen-greeter/releases/download/v0.1.0/sqlc-gen-greeter.wasm
+    sha256: afc486dac2068d741d7a4110146559d12a013fd0286f42a2fc7dcd802424ad07
+sql:
+- schema: schema.sql
+  queries: query.sql
+  engine: postgresql
+  codegen:
+  - out: gen
+    plugin: greeter
 ```
 
 For a complete working example see the following files:
@@ -59,35 +47,22 @@ the new files. The `plugin` key must reference a plugin defined in the
 top-level `plugins` map. The `options` are serialized to a string and passed on
 to the plugin itself.
 
-```json
-{
-  "version": "2",
-  "plugins": [
-    {
-      "name": "jsonb",
-      "process": {
-        "cmd": "sqlc-gen-json"
-      }
-    }
-  ],
-   "sql": [
-    {
-      "schema": "schema.sql",
-      "queries": "query.sql",
-      "engine": "postgresql",
-      "codegen": [
-        {
-          "out": "gen",
-          "plugin": "jsonb",
-          "options": {
-            "indent": "  ",
-            "filename": "codegen.json"
-          }
-        }
-      ]
-    }
-  ]
-}
+```yaml
+version: '2'
+plugins:
+- name: jsonb
+  process:
+    cmd: sqlc-gen-json
+sql:
+- schema: schema.sql
+  queries: query.sql
+  engine: postgresql
+  codegen:
+  - out: gen
+    plugin: jsonb
+    options:
+      indent: "  "
+      filename: codegen.json
 ```
 
 For a complete working example see the following files:
@@ -95,3 +70,31 @@ For a complete working example see the following files:
   - A process-based plugin that serializes the CodeGenRequest to JSON
 - [process_plugin_sqlc_gen_json](https://github.com/sqlc-dev/sqlc/tree/main/internal/endtoend/testdata/process_plugin_sqlc_gen_json)
   - An example project showing how to use a process-based plugin
+
+## Environment variables
+
+By default, plugins do not inherit access to environment variables. Instead,
+access can be configured on a per-variable basis. For example, if your plugin
+needs the `PATH` environment variable, add the `PATH` to the `env` option in the
+`plugins` collection.
+
+```yaml
+version: '2'
+sql:
+- schema: schema.sql
+  queries: query.sql
+  engine: postgresql
+  codegen:
+  - out: gen
+    plugin: test
+plugins:
+- name: test
+  env:
+  - PATH
+  wasm:
+    url: https://github.com/sqlc-dev/sqlc-gen-test/releases/download/v0.1.0/sqlc-gen-test.wasm
+    sha256: 138220eae508d4b65a5a8cea555edd155eb2290daf576b7a8b96949acfeb3790
+```
+
+The `SQLC_VERSION` environment variable will always be included in the
+environment, set to the version of the `sqlc` executable.
\ No newline at end of file
diff --git a/docs/reference/config.md b/docs/reference/config.md
index 51c6e6488..a9e0c40ed 100644
--- a/docs/reference/config.md
+++ b/docs/reference/config.md
@@ -316,6 +316,8 @@ Each mapping in the `plugins` collection has the following keys:
 
 - `name`:
   - The name of this plugin. Required
+- `env`
+  - A list of environment variables to pass to the plugin. By default, no environment variables are passed.
 - `process`: A mapping with a single `cmd` key
   - `cmd`:
     - The executable to call when using this plugin
@@ -333,6 +335,8 @@ plugins:
     url: "https://github.com/sqlc-dev/sqlc-gen-python/releases/download/v0.16.0-alpha/sqlc-gen-python.wasm"
     sha256: "428476c7408fd4c032da4ec74e8a7344f4fa75e0f98a5a3302f238283b9b95f2"
 - name: "js"
+  env:
+  - PATH
   process: 
     cmd: "sqlc-gen-json"
 ```
diff --git a/docs/requirements.txt b/docs/requirements.txt
index f69696c02..527a01988 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -17,11 +17,11 @@ requests==2.31.0
 snowballstemmer==2.2.0
 Sphinx==6.2.1
 sphinx-favicon==1.0.1
-sphinx-rtd-theme==1.2.2
+sphinx-rtd-theme==1.3.0
 sphinxcontrib-applehelp==1.0.7
 sphinxcontrib-devhelp==1.0.5
 sphinxcontrib-serializinghtml==1.1.9
-sphinxcontrib-htmlhelp==2.0.1
+sphinxcontrib-htmlhelp==2.0.4
 sphinxcontrib-jsmath==1.0.1
 sphinxcontrib-qthelp==1.0.6
 urllib3==2.0.4
diff --git a/go.mod b/go.mod
index 4718317de..db9a0412e 100644
--- a/go.mod
+++ b/go.mod
@@ -28,6 +28,8 @@ require (
 
 require (
 	github.com/bytecodealliance/wasmtime-go/v12 v12.0.0 // indirect
+	github.com/benbjohnson/clock v1.3.5 // indirect
+	github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
 )
@@ -44,19 +46,19 @@ require (
 	github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
 	github.com/jackc/pgtype v1.14.0
 	github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
-	github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 // indirect
-	github.com/pingcap/tidb/parser v0.0.0-20220725134311-c80026e61f00
+	github.com/pingcap/log v1.1.0 // indirect
+	github.com/pingcap/tidb/parser v0.0.0-20230815160630-b69fa21942d1
 	github.com/pkg/errors v0.9.1 // indirect
-	github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
+	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 	github.com/rogpeppe/go-internal v1.10.0 // indirect
 	github.com/stoewer/go-strcase v1.2.0 // indirect
-	go.uber.org/atomic v1.9.0 // indirect
-	go.uber.org/multierr v1.7.0 // indirect
-	go.uber.org/zap v1.19.1 // indirect
+	go.uber.org/atomic v1.11.0 // indirect
+	go.uber.org/multierr v1.11.0 // indirect
+	go.uber.org/zap v1.25.0 // indirect
 	golang.org/x/crypto v0.9.0 // indirect
-	golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
+	golang.org/x/exp v0.0.0-20230724220655-d98519c11495 // indirect
 	golang.org/x/net v0.10.0 // indirect
 	golang.org/x/sys v0.8.0 // indirect
-	golang.org/x/text v0.9.0 // indirect
-	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
+	golang.org/x/text v0.12.0 // indirect
+	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
 )
diff --git a/go.sum b/go.sum
index d5844c0ad..41af0a6b2 100644
--- a/go.sum
+++ b/go.sum
@@ -5,6 +5,8 @@ github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1 h
 github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
+github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/bytecodealliance/wasmtime-go/v11 v11.0.0 h1:SwLgbjbFpQ1tf5vIbWexaZABezBSL8WmzP+foLyi0lE=
 github.com/bytecodealliance/wasmtime-go/v11 v11.0.0/go.mod h1:9btfEuCkOP7EDR9a7LqDXrfQ7dtWeGlDHt3buV5UyjY=
 github.com/bytecodealliance/wasmtime-go/v12 v12.0.0 h1:Wga02UaZXYF3p0LIeL5xFp09/RI7UhjfT2uB0mLrwlw=
@@ -130,12 +132,19 @@ github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S
 github.com/pganalyze/pg_query_go/v4 v4.2.3 h1:cNLqyiVMasV7YGWyYV+fkXyHp32gDfXVNCqoHztEGNk=
 github.com/pganalyze/pg_query_go/v4 v4.2.3/go.mod h1:aEkDNOXNM5j0YGzaAapwJ7LB3dLNj+bvbWcLv1hOVqA=
 github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
+github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
 github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM=
 github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
+github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c h1:CgbKAHto5CQgWM9fSBIvaxsJHuGP0uM74HXtv3MyyGQ=
+github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c/go.mod h1:4qGtCB0QK0wBzKtFEGDhxXnSnbQApw1gc9siScUl8ew=
 github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 h1:SvWCbCPh1YeHd9yQLksvJYAgft6wLTY1aNG81tpyscQ=
 github.com/pingcap/log v0.0.0-20210906054005-afc726e70354/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4=
+github.com/pingcap/log v1.1.0 h1:ELiPxACz7vdo1qAvvaWJg1NrYFoY6gqAh/+Uo6aXdD8=
+github.com/pingcap/log v1.1.0/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4=
 github.com/pingcap/tidb/parser v0.0.0-20220725134311-c80026e61f00 h1:aDC/yAGx/jPEyrX+UPKV3GWg+4A4yG8ifuP6jBEhDi0=
 github.com/pingcap/tidb/parser v0.0.0-20220725134311-c80026e61f00/go.mod h1:wjvp+T3/T9XYt0nKqGX3Kc1AKuyUcfno6LTc6b2A6ew=
+github.com/pingcap/tidb/parser v0.0.0-20230815160630-b69fa21942d1 h1:FvX5fDJ32eblK9f6KJIOVujjtu3FDEfcRGHsEDfJ4kI=
+github.com/pingcap/tidb/parser v0.0.0-20230815160630-b69fa21942d1/go.mod h1:pWA6mNa/o7UTDKrg+4H75NdpRgpWRTox/cqQjaQ4ZBU=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -143,6 +152,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
+github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/riza-io/grpc-go v0.2.0 h1:2HxQKFVE7VuYstcJ8zqpN84VnAoJ4dCL6YFhJewNcHQ=
 github.com/riza-io/grpc-go v0.2.0/go.mod h1:2bDvR9KkKC3KhtlSHfR3dAXjUMT86kg4UfWFyVGWqi8=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -153,6 +164,7 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
 github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
 github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -188,15 +200,20 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4=
 go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
 go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
 go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
@@ -204,6 +221,8 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
 go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
 go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
 go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
+go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
+go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -219,6 +238,10 @@ golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
 golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
+golang.org/x/exp v0.0.0-20230724220655-d98519c11495 h1:zKGKw2WlGb8oPoRGqQ2PT8g2YoCN1w/YbbQjHXCdUWE=
+golang.org/x/exp v0.0.0-20230724220655-d98519c11495/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
+golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA=
+golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
@@ -271,6 +294,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
+golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@@ -307,12 +332,16 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs
 google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/cmd/generate.go b/internal/cmd/generate.go
index b38e73098..40e1dcbca 100644
--- a/internal/cmd/generate.go
+++ b/internal/cmd/generate.go
@@ -386,11 +386,13 @@ func codegen(ctx context.Context, combo config.CombinedSettings, sql outPair, re
 		case plug.Process != nil:
 			handler = &process.Runner{
 				Cmd: plug.Process.Cmd,
+				Env: plug.Env,
 			}
 		case plug.WASM != nil:
 			handler = &wasm.Runner{
 				URL:    plug.WASM.URL,
 				SHA256: plug.WASM.SHA256,
+				Env:    plug.Env,
 			}
 		default:
 			return "", nil, fmt.Errorf("unsupported plugin type")
diff --git a/internal/codegen/golang/imports.go b/internal/codegen/golang/imports.go
index b8552fd6a..71146ba64 100644
--- a/internal/codegen/golang/imports.go
+++ b/internal/codegen/golang/imports.go
@@ -243,8 +243,10 @@ func (i *importer) interfaceImports() fileImports {
 				}
 			}
 			if !q.Arg.isEmpty() {
-				if hasPrefixIgnoringSliceAndPointerPrefix(q.Arg.Type(), name) {
-					return true
+				for _, f := range q.Arg.Fields() {
+					if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) {
+						return true
+					}
 				}
 			}
 		}
@@ -311,16 +313,11 @@ func (i *importer) queryImports(filename string) fileImports {
 				}
 			}
 			if !q.Arg.isEmpty() {
-				if q.Arg.EmitStruct() {
-					for _, f := range q.Arg.Struct.Fields {
-						if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) {
-							return true
-						}
+				for _, f := range q.Arg.Fields() {
+					if hasPrefixIgnoringSliceAndPointerPrefix(f.Type, name) {
+						return true
 					}
 				}
-				if hasPrefixIgnoringSliceAndPointerPrefix(q.Arg.Type(), name) {
-					return true
-				}
 			}
 		}
 		return false
diff --git a/internal/codegen/golang/postgresql_type.go b/internal/codegen/golang/postgresql_type.go
index ae3e1278a..1936de1f3 100644
--- a/internal/codegen/golang/postgresql_type.go
+++ b/internal/codegen/golang/postgresql_type.go
@@ -343,7 +343,6 @@ func postgresType(req *plugin.CodeGenRequest, col *plugin.Column) string {
 		if driver == SQLDriverPGXV5 {
 			return "pgtype.Interval"
 		}
-
 		if notNull {
 			return "int64"
 		}
@@ -467,25 +466,47 @@ func postgresType(req *plugin.CodeGenRequest, col *plugin.Column) string {
 		return "interface{}"
 
 	case "bit", "varbit", "pg_catalog.bit", "pg_catalog.varbit":
-		if driver.IsPGX() {
+		if driver == SQLDriverPGXV5 {
 			return "pgtype.Bits"
 		}
+		if driver == SQLDriverPGXV4 {
+			return "pgtype.Varbit"
+		}
 
-	case "box":
-		if driver.IsPGX() {
-			return "pgtype.Box"
+	case "cid":
+		if driver == SQLDriverPGXV5 {
+			return "pgtype.Uint32"
+		}
+		if driver == SQLDriverPGXV4 {
+			return "pgtype.CID"
 		}
 
-	case "cid", "oid":
-		if driver.IsPGX() {
+	case "oid":
+		if driver == SQLDriverPGXV5 {
 			return "pgtype.Uint32"
 		}
+		if driver == SQLDriverPGXV4 {
+			return "pgtype.OID"
+		}
 
 	case "tid":
 		if driver.IsPGX() {
 			return "pgtype.TID"
 		}
 
+	case "xid":
+		if driver == SQLDriverPGXV5 {
+			return "pgtype.Uint32"
+		}
+		if driver == SQLDriverPGXV4 {
+			return "pgtype.XID"
+		}
+
+	case "box":
+		if driver.IsPGX() {
+			return "pgtype.Box"
+		}
+
 	case "circle":
 		if driver.IsPGX() {
 			return "pgtype.Circle"
diff --git a/internal/codegen/golang/templates/pgx/queryCode.tmpl b/internal/codegen/golang/templates/pgx/queryCode.tmpl
index 1736fa11f..18de5db2b 100644
--- a/internal/codegen/golang/templates/pgx/queryCode.tmpl
+++ b/internal/codegen/golang/templates/pgx/queryCode.tmpl
@@ -33,7 +33,7 @@ func (q *Queries) {{.MethodName}}(ctx context.Context, db DBTX, {{.Arg.Pair}}) (
 func (q *Queries) {{.MethodName}}(ctx context.Context, {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) {
 	row := q.db.QueryRow(ctx, {{.ConstantName}}, {{.Arg.Params}})
 {{- end}}
-	{{- if ne .Arg.Pair .Ret.Pair }}
+	{{- if or (ne .Arg.Pair .Ret.Pair) (ne .Arg.DefineType .Ret.DefineType) }}
 	var {{.Ret.Name}} {{.Ret.Type}}
 	{{- end}}
 	err := row.Scan({{.Ret.Scan}})
diff --git a/internal/codegen/golang/templates/stdlib/queryCode.tmpl b/internal/codegen/golang/templates/stdlib/queryCode.tmpl
index 6eca49cd1..cf56000ec 100644
--- a/internal/codegen/golang/templates/stdlib/queryCode.tmpl
+++ b/internal/codegen/golang/templates/stdlib/queryCode.tmpl
@@ -24,7 +24,7 @@ type {{.Ret.Type}} struct { {{- range .Ret.Struct.Fields}}
 {{end -}}
 func (q *Queries) {{.MethodName}}(ctx context.Context, {{ dbarg }} {{.Arg.Pair}}) ({{.Ret.DefineType}}, error) {
     {{- template "queryCodeStdExec" . }}
-	{{- if ne .Arg.Pair .Ret.Pair }}
+	{{- if or (ne .Arg.Pair .Ret.Pair) (ne .Arg.DefineType .Ret.DefineType) }}
 	var {{.Ret.Name}} {{.Ret.Type}}
 	{{- end}}
 	err := row.Scan({{.Ret.Scan}})
diff --git a/internal/compiler/expand.go b/internal/compiler/expand.go
index 8ea2fd2d2..29adfa316 100644
--- a/internal/compiler/expand.go
+++ b/internal/compiler/expand.go
@@ -38,12 +38,7 @@ func (c *Compiler) expand(qc *QueryCatalog, raw *ast.RawStmt) ([]source.Edit, er
 
 func (c *Compiler) quoteIdent(ident string) string {
 	if c.parser.IsReservedKeyword(ident) {
-		switch c.conf.Engine {
-		case config.EngineMySQL:
-			return "`" + ident + "`"
-		default:
-			return "\"" + ident + "\""
-		}
+		return c.quote(ident)
 	}
 	if c.conf.Engine == config.EnginePostgreSQL {
 		// camelCase means the column is also camelCase
@@ -54,6 +49,15 @@ func (c *Compiler) quoteIdent(ident string) string {
 	return ident
 }
 
+func (c *Compiler) quote(x string) string {
+	switch c.conf.Engine {
+	case config.EngineMySQL:
+		return "`" + x + "`"
+	default:
+		return "\"" + x + "\""
+	}
+}
+
 func (c *Compiler) expandStmt(qc *QueryCatalog, raw *ast.RawStmt, node ast.Node) ([]source.Edit, error) {
 	tables, err := c.sourceTables(qc, node)
 	if err != nil {
@@ -132,16 +136,36 @@ func (c *Compiler) expandStmt(qc *QueryCatalog, raw *ast.RawStmt, node ast.Node)
 		for _, p := range parts {
 			old = append(old, c.quoteIdent(p))
 		}
-		oldString := strings.Join(old, ".")
+
+		var oldString string
+		var oldFunc func(string) int
 
 		// use the sqlc.embed string instead
 		if embed, ok := qc.embeds.Find(ref); ok {
 			oldString = embed.Orig()
+		} else {
+			oldFunc = func(s string) int {
+				length := 0
+				for i, o := range old {
+					if hasSeparator := i > 0; hasSeparator {
+						length++
+					}
+					if strings.HasPrefix(s[length:], o) {
+						length += len(o)
+					} else if quoted := c.quote(o); strings.HasPrefix(s[length:], quoted) {
+						length += len(quoted)
+					} else {
+						length += len(o)
+					}
+				}
+				return length
+			}
 		}
 
 		edits = append(edits, source.Edit{
 			Location: res.Location - raw.StmtLocation,
 			Old:      oldString,
+			OldFunc:  oldFunc,
 			New:      strings.Join(cols, ", "),
 		})
 	}
diff --git a/internal/compiler/output_columns.go b/internal/compiler/output_columns.go
index fe7f3c30a..545869cf6 100644
--- a/internal/compiler/output_columns.go
+++ b/internal/compiler/output_columns.go
@@ -612,19 +612,26 @@ func (c *Compiler) sourceTables(qc *QueryCatalog, node ast.Node) ([]*Table, erro
 
 func outputColumnRefs(res *ast.ResTarget, tables []*Table, node *ast.ColumnRef) ([]*Column, error) {
 	parts := stringSlice(node.Fields)
-	var name, alias string
+	var schema, name, alias string
 	switch {
 	case len(parts) == 1:
 		name = parts[0]
 	case len(parts) == 2:
 		alias = parts[0]
 		name = parts[1]
+	case len(parts) == 3:
+		schema = parts[0]
+		alias = parts[1]
+		name = parts[2]
 	default:
 		return nil, fmt.Errorf("unknown number of fields: %d", len(parts))
 	}
 	var cols []*Column
 	var found int
 	for _, t := range tables {
+		if schema != "" && t.Rel.Schema != schema {
+			continue
+		}
 		if alias != "" && t.Rel.Name != alias {
 			continue
 		}
diff --git a/internal/config/config.go b/internal/config/config.go
index 1d3df66aa..6b3c665d9 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -79,7 +79,8 @@ type Cloud struct {
 }
 
 type Plugin struct {
-	Name    string `json:"name" yaml:"name"`
+	Name    string   `json:"name" yaml:"name"`
+	Env     []string `json:"env" yaml:"env"`
 	Process *struct {
 		Cmd string `json:"cmd" yaml:"cmd"`
 	} `json:"process" yaml:"process"`
diff --git a/internal/engine/dolphin/convert.go b/internal/engine/dolphin/convert.go
index 4a4478c65..5cca53697 100644
--- a/internal/engine/dolphin/convert.go
+++ b/internal/engine/dolphin/convert.go
@@ -1103,7 +1103,7 @@ func (c *cc) convertPatternInExpr(n *pcast.PatternInExpr) ast.Node {
 	return in
 }
 
-func (c *cc) convertPatternLikeExpr(n *pcast.PatternLikeExpr) ast.Node {
+func (c *cc) convertPatternLikeExpr(n *pcast.PatternLikeOrIlikeExpr) ast.Node {
 	return &ast.A_Expr{
 		Kind: ast.A_Expr_Kind(9),
 		Name: &ast.List{
@@ -1265,7 +1265,12 @@ func (c *cc) convertSetOprSelectList(n *pcast.SetOprSelectList) ast.Node {
 
 func (c *cc) convertSetOprStmt(n *pcast.SetOprStmt) ast.Node {
 	if n.SelectList != nil {
-		return c.convertSetOprSelectList(n.SelectList)
+		sn := c.convertSetOprSelectList(n.SelectList)
+		if ss, ok := sn.(*ast.SelectStmt); ok && n.Limit != nil {
+			ss.LimitOffset = c.convert(n.Limit.Offset)
+			ss.LimitCount = c.convert(n.Limit.Count)
+		}
+		return sn
 	}
 	return todo(n)
 }
@@ -1429,6 +1434,48 @@ func (c *cc) convertWindowSpec(n *pcast.WindowSpec) ast.Node {
 	return todo(n)
 }
 
+func (c *cc) convertCallStmt(n *pcast.CallStmt) ast.Node {
+	var funcname ast.List
+	for _, s := range []string{n.Procedure.Schema.L, n.Procedure.FnName.L} {
+		if s != "" {
+			funcname.Items = append(funcname.Items, NewIdentifier(s))
+		}
+	}
+	var args ast.List
+	for _, a := range n.Procedure.Args {
+		args.Items = append(args.Items, c.convert(a))
+	}
+	return &ast.CallStmt{
+		FuncCall: &ast.FuncCall{
+			Func: &ast.FuncName{
+				Schema: n.Procedure.Schema.L,
+				Name:   n.Procedure.FnName.L,
+			},
+			Funcname: &funcname,
+			Args:     &args,
+			Location: n.OriginTextPosition(),
+		},
+	}
+}
+
+func (c *cc) convertProcedureInfo(n *pcast.ProcedureInfo) ast.Node {
+	var params ast.List
+	for _, sp := range n.ProcedureParam {
+		paramName := sp.ParamName
+		params.Items = append(params.Items, &ast.FuncParam{
+			Name: &paramName,
+			Type: &ast.TypeName{Name: types.TypeToStr(sp.ParamType.GetType(), sp.ParamType.GetCharset())},
+		})
+	}
+	return &ast.CreateFunctionStmt{
+		Params: &params,
+		Func: &ast.FuncName{
+			Schema: n.ProcedureName.Schema.L,
+			Name:   n.ProcedureName.Name.L,
+		},
+	}
+}
+
 func (c *cc) convert(node pcast.Node) ast.Node {
 	switch n := node.(type) {
 
@@ -1483,6 +1530,9 @@ func (c *cc) convert(node pcast.Node) ast.Node {
 	case *pcast.ByItem:
 		return c.convertByItem(n)
 
+	case *pcast.CallStmt:
+		return c.convertCallStmt(n)
+
 	case *pcast.CaseExpr:
 		return c.convertCaseExpr(n)
 
@@ -1687,7 +1737,7 @@ func (c *cc) convert(node pcast.Node) ast.Node {
 	case *pcast.PatternInExpr:
 		return c.convertPatternInExpr(n)
 
-	case *pcast.PatternLikeExpr:
+	case *pcast.PatternLikeOrIlikeExpr:
 		return c.convertPatternLikeExpr(n)
 
 	case *pcast.PatternRegexpExpr:
@@ -1702,6 +1752,9 @@ func (c *cc) convert(node pcast.Node) ast.Node {
 	case *pcast.PrivElem:
 		return c.convertPrivElem(n)
 
+	case *pcast.ProcedureInfo:
+		return c.convertProcedureInfo(n)
+
 	case *pcast.RecoverTableStmt:
 		return c.convertRecoverTableStmt(n)
 
diff --git a/internal/engine/sqlite/convert.go b/internal/engine/sqlite/convert.go
index 7a9bfa6db..d1e9a8c05 100644
--- a/internal/engine/sqlite/convert.go
+++ b/internal/engine/sqlite/convert.go
@@ -375,13 +375,7 @@ func (c *cc) convertComparison(n *parser.Expr_comparisonContext) ast.Node {
 }
 
 func (c *cc) convertMultiSelect_stmtContext(n *parser.Select_stmtContext) ast.Node {
-	var tables []ast.Node
-	var cols []ast.Node
-	var where ast.Node
-	var groups = []ast.Node{}
-	var having ast.Node
-	var ctes []ast.Node
-
+	var ctes ast.List
 	if ct := n.Common_table_stmt(); ct != nil {
 		recursive := ct.RECURSIVE_() != nil
 		for _, cte := range ct.AllCommon_table_expression() {
@@ -390,7 +384,7 @@ func (c *cc) convertMultiSelect_stmtContext(n *parser.Select_stmtContext) ast.No
 			for _, col := range cte.AllColumn_name() {
 				cteCols.Items = append(cteCols.Items, NewIdentifier(col.GetText()))
 			}
-			ctes = append(ctes, &ast.CommonTableExpr{
+			ctes.Items = append(ctes.Items, &ast.CommonTableExpr{
 				Ctename:      &tableName,
 				Ctequery:     c.convert(cte.Select_stmt()),
 				Location:     cte.GetStart().GetStart(),
@@ -400,20 +394,24 @@ func (c *cc) convertMultiSelect_stmtContext(n *parser.Select_stmtContext) ast.No
 		}
 	}
 
-	for _, icore := range n.AllSelect_core() {
+	var selectStmt *ast.SelectStmt
+	for s, icore := range n.AllSelect_core() {
 		core, ok := icore.(*parser.Select_coreContext)
 		if !ok {
 			continue
 		}
-		cols = append(cols, c.getCols(core)...)
-		tables = append(tables, c.getTables(core)...)
+		cols := c.getCols(core)
+		tables := c.getTables(core)
 
+		var where ast.Node
 		i := 0
 		if core.WHERE_() != nil {
 			where = c.convert(core.Expr(i))
 			i++
 		}
 
+		var groups ast.List
+		var having ast.Node
 		if core.GROUP_() != nil {
 			l := len(core.AllExpr()) - i
 			if core.HAVING_() != nil {
@@ -422,33 +420,103 @@ func (c *cc) convertMultiSelect_stmtContext(n *parser.Select_stmtContext) ast.No
 			}
 
 			for i < l {
-				groups = append(groups, c.convert(core.Expr(i)))
+				groups.Items = append(groups.Items, c.convert(core.Expr(i)))
 				i++
 			}
 		}
-	}
-
-	window := &ast.List{Items: []ast.Node{}}
-	if n.Order_by_stmt() != nil {
-		window.Items = append(window.Items, c.convert(n.Order_by_stmt()))
+		var window ast.List
+		if core.WINDOW_() != nil {
+			for w, windowNameCtx := range core.AllWindow_name() {
+				windowName := identifier(windowNameCtx.GetText())
+				windowDef := core.Window_defn(w)
+
+				_ = windowDef.Base_window_name()
+				var partitionBy ast.List
+				if windowDef.PARTITION_() != nil {
+					for _, e := range windowDef.AllExpr() {
+						partitionBy.Items = append(partitionBy.Items, c.convert(e))
+					}
+				}
+				var orderBy ast.List
+				if windowDef.ORDER_() != nil {
+					for _, e := range windowDef.AllOrdering_term() {
+						oterm := e.(*parser.Ordering_termContext)
+						sortByDir := ast.SortByDirDefault
+						if ad := oterm.Asc_desc(); ad != nil {
+							if ad.ASC_() != nil {
+								sortByDir = ast.SortByDirAsc
+							} else {
+								sortByDir = ast.SortByDirDesc
+							}
+						}
+						sortByNulls := ast.SortByNullsDefault
+						if oterm.NULLS_() != nil {
+							if oterm.FIRST_() != nil {
+								sortByNulls = ast.SortByNullsFirst
+							} else {
+								sortByNulls = ast.SortByNullsLast
+							}
+						}
+
+						orderBy.Items = append(orderBy.Items, &ast.SortBy{
+							Node:        c.convert(oterm.Expr()),
+							SortbyDir:   sortByDir,
+							SortbyNulls: sortByNulls,
+							UseOp:       &ast.List{},
+						})
+					}
+				}
+				window.Items = append(window.Items, &ast.WindowDef{
+					Name:            &windowName,
+					PartitionClause: &partitionBy,
+					OrderClause:     &orderBy,
+					FrameOptions:    0, // todo
+					StartOffset:     &ast.TODO{},
+					EndOffset:       &ast.TODO{},
+					Location:        windowNameCtx.GetStart().GetStart(),
+				})
+			}
+		}
+		sel := &ast.SelectStmt{
+			FromClause:   &ast.List{Items: tables},
+			TargetList:   &ast.List{Items: cols},
+			WhereClause:  where,
+			GroupClause:  &groups,
+			HavingClause: having,
+			WindowClause: &window,
+			ValuesLists:  &ast.List{},
+		}
+		if selectStmt == nil {
+			selectStmt = sel
+		} else {
+			co := n.Compound_operator(s - 1)
+			so := ast.None
+			all := false
+			switch {
+			case co.UNION_() != nil:
+				so = ast.Union
+				all = co.ALL_() != nil
+			case co.INTERSECT_() != nil:
+				so = ast.Intersect
+			case co.EXCEPT_() != nil:
+				so = ast.Except
+			}
+			selectStmt = &ast.SelectStmt{
+				TargetList: &ast.List{},
+				FromClause: &ast.List{},
+				Op:         so,
+				All:        all,
+				Larg:       selectStmt,
+				Rarg:       sel,
+			}
+		}
 	}
 
 	limitCount, limitOffset := c.convertLimit_stmtContext(n.Limit_stmt())
-
-	return &ast.SelectStmt{
-		FromClause:   &ast.List{Items: tables},
-		TargetList:   &ast.List{Items: cols},
-		WhereClause:  where,
-		GroupClause:  &ast.List{Items: groups},
-		HavingClause: having,
-		WindowClause: window,
-		LimitCount:   limitCount,
-		LimitOffset:  limitOffset,
-		ValuesLists:  &ast.List{},
-		WithClause: &ast.WithClause{
-			Ctes: &ast.List{Items: ctes},
-		},
-	}
+	selectStmt.LimitCount = limitCount
+	selectStmt.LimitOffset = limitOffset
+	selectStmt.WithClause = &ast.WithClause{Ctes: &ctes}
+	return selectStmt
 }
 
 func (c *cc) convertExprListContext(n *parser.Expr_listContext) ast.Node {
@@ -460,17 +528,46 @@ func (c *cc) convertExprListContext(n *parser.Expr_listContext) ast.Node {
 }
 
 func (c *cc) getTables(core *parser.Select_coreContext) []ast.Node {
-	var tables []ast.Node
-	tables = append(tables, c.convertTablesOrSubquery(core.AllTable_or_subquery())...)
-
 	if core.Join_clause() != nil {
-		join, ok := core.Join_clause().(*parser.Join_clauseContext)
-		if ok {
-			tables = append(tables, c.convertTablesOrSubquery(join.AllTable_or_subquery())...)
+		join := core.Join_clause().(*parser.Join_clauseContext)
+		tables := c.convertTablesOrSubquery(join.AllTable_or_subquery())
+		table := tables[0]
+		for i, t := range tables[1:] {
+			joinExpr := &ast.JoinExpr{
+				Larg: table,
+				Rarg: t,
+			}
+			jo := join.Join_operator(i)
+			if jo.NATURAL_() != nil {
+				joinExpr.IsNatural = true
+			}
+			switch {
+			case jo.CROSS_() != nil || jo.INNER_() != nil:
+				joinExpr.Jointype = ast.JoinTypeInner
+			case jo.LEFT_() != nil:
+				joinExpr.Jointype = ast.JoinTypeLeft
+			case jo.RIGHT_() != nil:
+				joinExpr.Jointype = ast.JoinTypeRight
+			case jo.FULL_() != nil:
+				joinExpr.Jointype = ast.JoinTypeFull
+			}
+			jc := join.Join_constraint(i)
+			switch {
+			case jc.ON_() != nil:
+				joinExpr.Quals = c.convert(jc.Expr())
+			case jc.USING_() != nil:
+				var using ast.List
+				for _, cn := range jc.AllColumn_name() {
+					using.Items = append(using.Items, NewIdentifier(cn.GetText()))
+				}
+				joinExpr.UsingClause = &using
+			}
+			table = joinExpr
 		}
+		return []ast.Node{table}
+	} else {
+		return c.convertTablesOrSubquery(core.AllTable_or_subquery())
 	}
-
-	return tables
 }
 
 func (c *cc) getCols(core *parser.Select_coreContext) []ast.Node {
@@ -767,7 +864,7 @@ func (c *cc) convertInsert_stmtContext(n *parser.Insert_stmtContext) ast.Node {
 		rel.Schemaname = &schemaName
 	}
 	if n.Table_alias() != nil {
-		tableAlias := n.Table_alias().GetText()
+		tableAlias := identifier(n.Table_alias().GetText())
 		rel.Alias = &ast.Alias{
 			Aliasname: &tableAlias,
 		}
@@ -837,7 +934,7 @@ func (c *cc) convertTablesOrSubquery(n []parser.ITable_or_subqueryContext) []ast
 				rv.Schemaname = &schema
 			}
 			if from.Table_alias() != nil {
-				alias := from.Table_alias().GetText()
+				alias := identifier(from.Table_alias().GetText())
 				rv.Alias = &ast.Alias{Aliasname: &alias}
 			}
 			if from.Table_alias_fallback() != nil {
@@ -870,7 +967,7 @@ func (c *cc) convertTablesOrSubquery(n []parser.ITable_or_subqueryContext) []ast
 			}
 
 			if from.Table_alias() != nil {
-				alias := from.Table_alias().GetText()
+				alias := identifier(from.Table_alias().GetText())
 				rf.Alias = &ast.Alias{Aliasname: &alias}
 			}
 
@@ -881,7 +978,7 @@ func (c *cc) convertTablesOrSubquery(n []parser.ITable_or_subqueryContext) []ast
 			}
 
 			if from.Table_alias() != nil {
-				alias := from.Table_alias().GetText()
+				alias := identifier(from.Table_alias().GetText())
 				rs.Alias = &ast.Alias{Aliasname: &alias}
 			}
 
diff --git a/internal/ext/process/gen.go b/internal/ext/process/gen.go
index dc39a15fd..7a4803844 100644
--- a/internal/ext/process/gen.go
+++ b/internal/ext/process/gen.go
@@ -5,6 +5,7 @@ import (
 	"context"
 	"errors"
 	"fmt"
+	"os"
 	"os/exec"
 
 	"google.golang.org/protobuf/proto"
@@ -14,6 +15,7 @@ import (
 
 type Runner struct {
 	Cmd string
+	Env []string
 }
 
 // TODO: Update the gen func signature to take a ctx
@@ -34,6 +36,9 @@ func (r Runner) Generate(ctx context.Context, req *plugin.CodeGenRequest) (*plug
 	cmd.Env = []string{
 		fmt.Sprintf("SQLC_VERSION=%s", req.SqlcVersion),
 	}
+	for _, key := range r.Env {
+		cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, os.Getenv(key)))
+	}
 
 	out, err := cmd.Output()
 	if err != nil {
diff --git a/internal/ext/wasm/wasm.go b/internal/ext/wasm/wasm.go
index 9b10c08d5..e643ea7a3 100644
--- a/internal/ext/wasm/wasm.go
+++ b/internal/ext/wasm/wasm.go
@@ -47,6 +47,7 @@ func cacheDir() (string, error) {
 type Runner struct {
 	URL    string
 	SHA256 string
+	Env    []string
 }
 
 var flight singleflight.Group
@@ -255,6 +256,14 @@ func (r *Runner) Generate(ctx context.Context, req *plugin.CodeGenRequest) (*plu
 	wasiConfig.SetStdoutFile(stdoutPath)
 	wasiConfig.SetStderrFile(stderrPath)
 
+	keys := []string{"SQLC_VERSION"}
+	vals := []string{req.SqlcVersion}
+	for _, key := range r.Env {
+		keys = append(keys, key)
+		vals = append(vals, os.Getenv(key))
+	}
+	wasiConfig.SetEnv(keys, vals)
+
 	store := wasmtime.NewStore(engine)
 	store.SetWasi(wasiConfig)
 
diff --git a/internal/source/code.go b/internal/source/code.go
index 9a6ed077d..f34e3e368 100644
--- a/internal/source/code.go
+++ b/internal/source/code.go
@@ -12,6 +12,7 @@ type Edit struct {
 	Location int
 	Old      string
 	New      string
+	OldFunc  func(string) int
 }
 
 func LineNumber(source string, head int) (int, int) {
@@ -63,8 +64,14 @@ func Mutate(raw string, a []Edit) (string, error) {
 		if start > len(s) || start < 0 {
 			return "", fmt.Errorf("edit start location is out of bounds")
 		}
+		var oldLen int
+		if edit.OldFunc != nil {
+			oldLen = edit.OldFunc(s[start:])
+		} else {
+			oldLen = len(edit.Old)
+		}
 
-		stop := edit.Location + len(edit.Old)
+		stop := edit.Location + oldLen
 		if stop > len(s) {
 			return "", fmt.Errorf("edit stop location is out of bounds")
 		}
@@ -73,7 +80,7 @@ func Mutate(raw string, a []Edit) (string, error) {
 		// this edit overlaps the previous one (and is therefore a developer error)
 		if idx != 0 {
 			prevEdit := a[idx-1]
-			if prevEdit.Location < edit.Location+len(edit.Old) {
+			if prevEdit.Location < edit.Location+oldLen {
 				return "", fmt.Errorf("2 edits overlap")
 			}
 		}
diff --git a/internal/sql/ast/sort_by_dir.go b/internal/sql/ast/sort_by_dir.go
index f7f8d5395..3ebd212a7 100644
--- a/internal/sql/ast/sort_by_dir.go
+++ b/internal/sql/ast/sort_by_dir.go
@@ -5,3 +5,11 @@ type SortByDir uint
 func (n *SortByDir) Pos() int {
 	return 0
 }
+
+const (
+	SortByDirUndefined SortByDir = 0
+	SortByDirDefault   SortByDir = 1
+	SortByDirAsc       SortByDir = 2
+	SortByDirDesc      SortByDir = 3
+	SortByDirUsing     SortByDir = 4
+)
diff --git a/internal/sql/ast/sort_by_nulls.go b/internal/sql/ast/sort_by_nulls.go
index c4d67c5d7..512b5a14e 100644
--- a/internal/sql/ast/sort_by_nulls.go
+++ b/internal/sql/ast/sort_by_nulls.go
@@ -5,3 +5,10 @@ type SortByNulls uint
 func (n *SortByNulls) Pos() int {
 	return 0
 }
+
+const (
+	SortByNullsUndefined SortByNulls = 0
+	SortByNullsDefault   SortByNulls = 1
+	SortByNullsFirst     SortByNulls = 2
+	SortByNullsLast      SortByNulls = 3
+)
diff --git a/scripts/regenerate/main.go b/scripts/regenerate/main.go
index 3bb2ba3e6..b2bcb2089 100644
--- a/scripts/regenerate/main.go
+++ b/scripts/regenerate/main.go
@@ -56,6 +56,7 @@ func regenerate(dir string) error {
 			}
 
 			cmd := exec.Command("sqlc-dev", "generate")
+			cmd.Env = append(cmd.Env, "SQLC_DUMMY_VALUE=true")
 			cmd.Dir = cwd
 			out, failed := cmd.CombinedOutput()
 			if failed != nil && !expectFailure {


Test patch:
diff --git a/examples/booktest/sqlite/db_test.go b/examples/booktest/sqlite/db_test.go
index d1da918ba..f169c7914 100644
--- a/examples/booktest/sqlite/db_test.go
+++ b/examples/booktest/sqlite/db_test.go
@@ -146,7 +146,7 @@ func TestBooks(t *testing.T) {
 		t.Fatal(err)
 	}
 	for _, ab := range res {
-		t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tag: '%v'\n", ab.BookID, ab.Title, ab.Name, ab.Isbn, ab.Tag)
+		t.Logf("Book %d: '%s', Author: '%s', ISBN: '%s' Tag: '%v'\n", ab.BookID, ab.Title, ab.Name.String, ab.Isbn, ab.Tag)
 	}
 
 	// TODO: call say_hello(varchar)
diff --git a/examples/booktest/sqlite/query.sql.go b/examples/booktest/sqlite/query.sql.go
index 2786ab392..4dbc42eca 100644
--- a/examples/booktest/sqlite/query.sql.go
+++ b/examples/booktest/sqlite/query.sql.go
@@ -7,6 +7,7 @@ package booktest
 
 import (
 	"context"
+	"database/sql"
 	"strings"
 	"time"
 )
@@ -26,7 +27,7 @@ WHERE tag IN (/*SLICE:tags*/?)
 type BooksByTagsRow struct {
 	BookID int64
 	Title  string
-	Name   string
+	Name   sql.NullString
 	Isbn   string
 	Tag    string
 }
diff --git a/internal/endtoend/endtoend_test.go b/internal/endtoend/endtoend_test.go
index 5df39c44e..e91e9f9c5 100644
--- a/internal/endtoend/endtoend_test.go
+++ b/internal/endtoend/endtoend_test.go
@@ -75,6 +75,10 @@ func BenchmarkExamples(b *testing.B) {
 }
 
 func TestReplay(t *testing.T) {
+	// Ensure that this environment variable is always set to true when running
+	// end-to-end tests
+	os.Setenv("SQLC_DUMMY_VALUE", "true")
+
 	t.Parallel()
 	ctx := context.Background()
 	var dirs []string
diff --git a/internal/endtoend/testdata/bit_string/pgx/v4/go/db.go b/internal/endtoend/testdata/bit_string/pgx/v4/go/db.go
new file mode 100644
index 000000000..f0ea7fd21
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v4/go/db.go
@@ -0,0 +1,32 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+
+	"github.com/jackc/pgconn"
+	"github.com/jackc/pgx/v4"
+)
+
+type DBTX interface {
+	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
+	Query(context.Context, string, ...interface{}) (pgx.Rows, error)
+	QueryRow(context.Context, string, ...interface{}) pgx.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx pgx.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/bit_string/pgx/v4/go/models.go b/internal/endtoend/testdata/bit_string/pgx/v4/go/models.go
new file mode 100644
index 000000000..99319485d
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v4/go/models.go
@@ -0,0 +1,16 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"github.com/jackc/pgtype"
+)
+
+type TestTable struct {
+	VBitNull    pgtype.Varbit
+	VVarbitNull pgtype.Varbit
+	VBit        pgtype.Varbit
+	VVarbit     pgtype.Varbit
+}
diff --git a/internal/endtoend/testdata/bit_string/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/bit_string/pgx/v4/go/query.sql.go
new file mode 100644
index 000000000..5a1b4455d
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v4/go/query.sql.go
@@ -0,0 +1,40 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const selectTest = `-- name: SelectTest :many
+SELECT v_bit_null, v_varbit_null, v_bit, v_varbit
+from test_table
+`
+
+func (q *Queries) SelectTest(ctx context.Context) ([]TestTable, error) {
+	rows, err := q.db.Query(ctx, selectTest)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []TestTable
+	for rows.Next() {
+		var i TestTable
+		if err := rows.Scan(
+			&i.VBitNull,
+			&i.VVarbitNull,
+			&i.VBit,
+			&i.VVarbit,
+		); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/bit_string/pgx/v4/query.sql b/internal/endtoend/testdata/bit_string/pgx/v4/query.sql
new file mode 100644
index 000000000..20405dc52
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v4/query.sql
@@ -0,0 +1,11 @@
+CREATE TABLE test_table
+(
+    v_bit_null     bit(3),
+    v_varbit_null  bit varying(3),
+    v_bit          bit(3)             not null,
+    v_varbit       bit varying(3)     not null
+);
+
+-- name: SelectTest :many
+SELECT *
+from test_table;
diff --git a/internal/endtoend/testdata/bit_string/pgx/v4/sqlc.json b/internal/endtoend/testdata/bit_string/pgx/v4/sqlc.json
new file mode 100644
index 000000000..9403bd027
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v4/sqlc.json
@@ -0,0 +1,13 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "path": "go",
+      "engine": "postgresql",
+      "sql_package": "pgx/v4",
+      "name": "querytest",
+      "schema": "query.sql",
+      "queries": "query.sql"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/bit_string/pgx/v5/go/db.go b/internal/endtoend/testdata/bit_string/pgx/v5/go/db.go
new file mode 100644
index 000000000..e715a0f40
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v5/go/db.go
@@ -0,0 +1,32 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+type DBTX interface {
+	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
+	Query(context.Context, string, ...interface{}) (pgx.Rows, error)
+	QueryRow(context.Context, string, ...interface{}) pgx.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx pgx.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/bit_string/pgx/v5/go/models.go b/internal/endtoend/testdata/bit_string/pgx/v5/go/models.go
new file mode 100644
index 000000000..bd25c787b
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v5/go/models.go
@@ -0,0 +1,16 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+type TestTable struct {
+	VBitNull    pgtype.Bits
+	VVarbitNull pgtype.Bits
+	VBit        pgtype.Bits
+	VVarbit     pgtype.Bits
+}
diff --git a/internal/endtoend/testdata/bit_string/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/bit_string/pgx/v5/go/query.sql.go
new file mode 100644
index 000000000..5a1b4455d
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v5/go/query.sql.go
@@ -0,0 +1,40 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const selectTest = `-- name: SelectTest :many
+SELECT v_bit_null, v_varbit_null, v_bit, v_varbit
+from test_table
+`
+
+func (q *Queries) SelectTest(ctx context.Context) ([]TestTable, error) {
+	rows, err := q.db.Query(ctx, selectTest)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []TestTable
+	for rows.Next() {
+		var i TestTable
+		if err := rows.Scan(
+			&i.VBitNull,
+			&i.VVarbitNull,
+			&i.VBit,
+			&i.VVarbit,
+		); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/bit_string/pgx/v5/query.sql b/internal/endtoend/testdata/bit_string/pgx/v5/query.sql
new file mode 100644
index 000000000..20405dc52
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v5/query.sql
@@ -0,0 +1,11 @@
+CREATE TABLE test_table
+(
+    v_bit_null     bit(3),
+    v_varbit_null  bit varying(3),
+    v_bit          bit(3)             not null,
+    v_varbit       bit varying(3)     not null
+);
+
+-- name: SelectTest :many
+SELECT *
+from test_table;
diff --git a/internal/endtoend/testdata/bit_string/pgx/v5/sqlc.json b/internal/endtoend/testdata/bit_string/pgx/v5/sqlc.json
new file mode 100644
index 000000000..6645ccbd1
--- /dev/null
+++ b/internal/endtoend/testdata/bit_string/pgx/v5/sqlc.json
@@ -0,0 +1,13 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "path": "go",
+      "engine": "postgresql",
+      "sql_package": "pgx/v5",
+      "name": "querytest",
+      "schema": "query.sql",
+      "queries": "query.sql"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/db.go b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/db.go
new file mode 100644
index 000000000..f0ea7fd21
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/db.go
@@ -0,0 +1,32 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+
+	"github.com/jackc/pgconn"
+	"github.com/jackc/pgx/v4"
+)
+
+type DBTX interface {
+	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
+	Query(context.Context, string, ...interface{}) (pgx.Rows, error)
+	QueryRow(context.Context, string, ...interface{}) pgx.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx pgx.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/models.go b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/models.go
new file mode 100644
index 000000000..ad38e1e2b
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/models.go
@@ -0,0 +1,20 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"github.com/jackc/pgtype"
+)
+
+type TestTable struct {
+	VCidNull pgtype.CID
+	VOidNull pgtype.OID
+	VTidNull pgtype.TID
+	VXidNull pgtype.XID
+	VCid     pgtype.CID
+	VOid     pgtype.OID
+	VTid     pgtype.TID
+	VXid     pgtype.XID
+}
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/query.sql.go
new file mode 100644
index 000000000..c10d3b33f
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/go/query.sql.go
@@ -0,0 +1,44 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const selectTest = `-- name: SelectTest :many
+SELECT v_cid_null, v_oid_null, v_tid_null, v_xid_null, v_cid, v_oid, v_tid, v_xid
+from test_table
+`
+
+func (q *Queries) SelectTest(ctx context.Context) ([]TestTable, error) {
+	rows, err := q.db.Query(ctx, selectTest)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []TestTable
+	for rows.Next() {
+		var i TestTable
+		if err := rows.Scan(
+			&i.VCidNull,
+			&i.VOidNull,
+			&i.VTidNull,
+			&i.VXidNull,
+			&i.VCid,
+			&i.VOid,
+			&i.VTid,
+			&i.VXid,
+		); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/query.sql b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/query.sql
new file mode 100644
index 000000000..b25692dab
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/query.sql
@@ -0,0 +1,15 @@
+CREATE TABLE test_table
+(
+    v_cid_null     cid,
+    v_oid_null     oid,
+    v_tid_null     tid,
+    v_xid_null     xid,
+    v_cid          cid     not null,
+    v_oid          oid     not null,
+    v_tid          tid     not null,
+    v_xid          xid     not null
+);
+
+-- name: SelectTest :many
+SELECT *
+from test_table;
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/sqlc.json b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/sqlc.json
new file mode 100644
index 000000000..9403bd027
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v4/sqlc.json
@@ -0,0 +1,13 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "path": "go",
+      "engine": "postgresql",
+      "sql_package": "pgx/v4",
+      "name": "querytest",
+      "schema": "query.sql",
+      "queries": "query.sql"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/db.go b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/db.go
new file mode 100644
index 000000000..e715a0f40
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/db.go
@@ -0,0 +1,32 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+type DBTX interface {
+	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
+	Query(context.Context, string, ...interface{}) (pgx.Rows, error)
+	QueryRow(context.Context, string, ...interface{}) pgx.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx pgx.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/models.go b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/models.go
new file mode 100644
index 000000000..e8b60c63f
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/models.go
@@ -0,0 +1,20 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+type TestTable struct {
+	VCidNull pgtype.Uint32
+	VOidNull pgtype.Uint32
+	VTidNull pgtype.TID
+	VXidNull pgtype.Uint32
+	VCid     pgtype.Uint32
+	VOid     pgtype.Uint32
+	VTid     pgtype.TID
+	VXid     pgtype.Uint32
+}
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/query.sql.go
new file mode 100644
index 000000000..c10d3b33f
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/go/query.sql.go
@@ -0,0 +1,44 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const selectTest = `-- name: SelectTest :many
+SELECT v_cid_null, v_oid_null, v_tid_null, v_xid_null, v_cid, v_oid, v_tid, v_xid
+from test_table
+`
+
+func (q *Queries) SelectTest(ctx context.Context) ([]TestTable, error) {
+	rows, err := q.db.Query(ctx, selectTest)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []TestTable
+	for rows.Next() {
+		var i TestTable
+		if err := rows.Scan(
+			&i.VCidNull,
+			&i.VOidNull,
+			&i.VTidNull,
+			&i.VXidNull,
+			&i.VCid,
+			&i.VOid,
+			&i.VTid,
+			&i.VXid,
+		); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/query.sql b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/query.sql
new file mode 100644
index 000000000..b25692dab
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/query.sql
@@ -0,0 +1,15 @@
+CREATE TABLE test_table
+(
+    v_cid_null     cid,
+    v_oid_null     oid,
+    v_tid_null     tid,
+    v_xid_null     xid,
+    v_cid          cid     not null,
+    v_oid          oid     not null,
+    v_tid          tid     not null,
+    v_xid          xid     not null
+);
+
+-- name: SelectTest :many
+SELECT *
+from test_table;
diff --git a/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/sqlc.json b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/sqlc.json
new file mode 100644
index 000000000..6645ccbd1
--- /dev/null
+++ b/internal/endtoend/testdata/cid_oid_tid_xid/pgx/v5/sqlc.json
@@ -0,0 +1,13 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "path": "go",
+      "engine": "postgresql",
+      "sql_package": "pgx/v5",
+      "name": "querytest",
+      "schema": "query.sql",
+      "queries": "query.sql"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/ddl_create_procedure/mysql/go/db.go b/internal/endtoend/testdata/ddl_create_procedure/mysql/go/db.go
new file mode 100644
index 000000000..57406b68e
--- /dev/null
+++ b/internal/endtoend/testdata/ddl_create_procedure/mysql/go/db.go
@@ -0,0 +1,31 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+	"database/sql"
+)
+
+type DBTX interface {
+	ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
+	PrepareContext(context.Context, string) (*sql.Stmt, error)
+	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
+	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx *sql.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/ddl_create_procedure/mysql/go/models.go b/internal/endtoend/testdata/ddl_create_procedure/mysql/go/models.go
new file mode 100644
index 000000000..79f7ff39d
--- /dev/null
+++ b/internal/endtoend/testdata/ddl_create_procedure/mysql/go/models.go
@@ -0,0 +1,13 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"database/sql"
+)
+
+type Tbl struct {
+	Value sql.NullInt32
+}
diff --git a/internal/endtoend/testdata/ddl_create_procedure/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_create_procedure/mysql/go/query.sql.go
new file mode 100644
index 000000000..9e840218c
--- /dev/null
+++ b/internal/endtoend/testdata/ddl_create_procedure/mysql/go/query.sql.go
@@ -0,0 +1,47 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const callInsertData = `-- name: CallInsertData :exec
+CALL insert_data(?, ?)
+`
+
+type CallInsertDataParams struct {
+	A int32
+	B int32
+}
+
+func (q *Queries) CallInsertData(ctx context.Context, arg CallInsertDataParams) error {
+	_, err := q.db.ExecContext(ctx, callInsertData, arg.A, arg.B)
+	return err
+}
+
+const callInsertDataNoArgs = `-- name: CallInsertDataNoArgs :exec
+CALL insert_data(1, 2)
+`
+
+func (q *Queries) CallInsertDataNoArgs(ctx context.Context) error {
+	_, err := q.db.ExecContext(ctx, callInsertDataNoArgs)
+	return err
+}
+
+const callInsertDataSqlcArgs = `-- name: CallInsertDataSqlcArgs :exec
+CALL insert_data(?, ?)
+`
+
+type CallInsertDataSqlcArgsParams struct {
+	Foo int32
+	Bar int32
+}
+
+func (q *Queries) CallInsertDataSqlcArgs(ctx context.Context, arg CallInsertDataSqlcArgsParams) error {
+	_, err := q.db.ExecContext(ctx, callInsertDataSqlcArgs, arg.Foo, arg.Bar)
+	return err
+}
diff --git a/internal/endtoend/testdata/ddl_create_procedure/mysql/query.sql b/internal/endtoend/testdata/ddl_create_procedure/mysql/query.sql
new file mode 100644
index 000000000..ff9bbadf2
--- /dev/null
+++ b/internal/endtoend/testdata/ddl_create_procedure/mysql/query.sql
@@ -0,0 +1,8 @@
+-- name: CallInsertData :exec
+CALL insert_data(?, ?);
+
+-- name: CallInsertDataNoArgs :exec
+CALL insert_data(1, 2);
+
+-- name: CallInsertDataSqlcArgs :exec
+CALL insert_data(sqlc.arg('foo'), sqlc.arg('bar'));
diff --git a/internal/endtoend/testdata/ddl_create_procedure/mysql/schema.sql b/internal/endtoend/testdata/ddl_create_procedure/mysql/schema.sql
new file mode 100644
index 000000000..e3f2d0af3
--- /dev/null
+++ b/internal/endtoend/testdata/ddl_create_procedure/mysql/schema.sql
@@ -0,0 +1,9 @@
+CREATE TABLE tbl (
+    value int
+);
+
+CREATE PROCEDURE insert_data(a int, b int)
+BEGIN
+    INSERT INTO tbl VALUES (a);
+    INSERT INTO tbl VALUES (b);
+END;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/ddl_create_procedure/mysql/sqlc.json b/internal/endtoend/testdata/ddl_create_procedure/mysql/sqlc.json
new file mode 100644
index 000000000..e41c39e8b
--- /dev/null
+++ b/internal/endtoend/testdata/ddl_create_procedure/mysql/sqlc.json
@@ -0,0 +1,12 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "path": "go",
+      "engine": "mysql",
+      "name": "querytest",
+      "schema": "schema.sql",
+      "queries": "query.sql"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/full_outer_join/sqlite/go/query.sql.go b/internal/endtoend/testdata/full_outer_join/sqlite/go/query.sql.go
index bc37d4346..4e4826fb7 100644
--- a/internal/endtoend/testdata/full_outer_join/sqlite/go/query.sql.go
+++ b/internal/endtoend/testdata/full_outer_join/sqlite/go/query.sql.go
@@ -7,6 +7,7 @@ package querytest
 
 import (
 	"context"
+	"database/sql"
 )
 
 const getAuthor = `-- name: GetAuthor :one
@@ -17,10 +18,10 @@ WHERE a.id = ? LIMIT 1
 `
 
 type GetAuthorRow struct {
-	ID    int64
-	Name  string
-	ID_2  int64
-	Title string
+	ID    sql.NullInt64
+	Name  sql.NullString
+	ID_2  sql.NullInt64
+	Title sql.NullString
 }
 
 func (q *Queries) GetAuthor(ctx context.Context, id int64) (GetAuthorRow, error) {
diff --git a/internal/endtoend/testdata/geometric/pgx/v4/go/db.go b/internal/endtoend/testdata/geometric/pgx/v4/go/db.go
new file mode 100644
index 000000000..f0ea7fd21
--- /dev/null
+++ b/internal/endtoend/testdata/geometric/pgx/v4/go/db.go
@@ -0,0 +1,32 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+
+	"github.com/jackc/pgconn"
+	"github.com/jackc/pgx/v4"
+)
+
+type DBTX interface {
+	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
+	Query(context.Context, string, ...interface{}) (pgx.Rows, error)
+	QueryRow(context.Context, string, ...interface{}) pgx.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx pgx.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/geometric/pgx/v4/go/models.go b/internal/endtoend/testdata/geometric/pgx/v4/go/models.go
new file mode 100644
index 000000000..93fe7d6ad
--- /dev/null
+++ b/internal/endtoend/testdata/geometric/pgx/v4/go/models.go
@@ -0,0 +1,26 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"github.com/jackc/pgtype"
+)
+
+type TestTable struct {
+	VBoxNull     pgtype.Box
+	VCircleNull  pgtype.Circle
+	VLineNull    pgtype.Line
+	VLsegNull    pgtype.Lseg
+	VPathNull    pgtype.Path
+	VPointNull   pgtype.Point
+	VPolygonNull pgtype.Polygon
+	VBox         pgtype.Box
+	VCircle      pgtype.Circle
+	VLine        pgtype.Line
+	VLseg        pgtype.Lseg
+	VPath        pgtype.Path
+	VPoint       pgtype.Point
+	VPolygon     pgtype.Polygon
+}
diff --git a/internal/endtoend/testdata/geometric/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/geometric/pgx/v4/go/query.sql.go
new file mode 100644
index 000000000..b291917c5
--- /dev/null
+++ b/internal/endtoend/testdata/geometric/pgx/v4/go/query.sql.go
@@ -0,0 +1,50 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const selectTest = `-- name: SelectTest :many
+SELECT v_box_null, v_circle_null, v_line_null, v_lseg_null, v_path_null, v_point_null, v_polygon_null, v_box, v_circle, v_line, v_lseg, v_path, v_point, v_polygon
+from test_table
+`
+
+func (q *Queries) SelectTest(ctx context.Context) ([]TestTable, error) {
+	rows, err := q.db.Query(ctx, selectTest)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []TestTable
+	for rows.Next() {
+		var i TestTable
+		if err := rows.Scan(
+			&i.VBoxNull,
+			&i.VCircleNull,
+			&i.VLineNull,
+			&i.VLsegNull,
+			&i.VPathNull,
+			&i.VPointNull,
+			&i.VPolygonNull,
+			&i.VBox,
+			&i.VCircle,
+			&i.VLine,
+			&i.VLseg,
+			&i.VPath,
+			&i.VPoint,
+			&i.VPolygon,
+		); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/geometric/pgx/v4/query.sql b/internal/endtoend/testdata/geometric/pgx/v4/query.sql
new file mode 100644
index 000000000..e6084a002
--- /dev/null
+++ b/internal/endtoend/testdata/geometric/pgx/v4/query.sql
@@ -0,0 +1,21 @@
+CREATE TABLE test_table
+(
+    v_box_null     box,
+    v_circle_null  circle,
+    v_line_null    line,
+    v_lseg_null    lseg,
+    v_path_null    path,
+    v_point_null   point,
+    v_polygon_null polygon,
+    v_box          box     not null,
+    v_circle       circle  not null,
+    v_line         line    not null,
+    v_lseg         lseg    not null,
+    v_path         path    not null,
+    v_point        point   not null,
+    v_polygon      polygon not null
+);
+
+-- name: SelectTest :many
+SELECT *
+from test_table;
diff --git a/internal/endtoend/testdata/geometric/pgx/v4/sqlc.json b/internal/endtoend/testdata/geometric/pgx/v4/sqlc.json
new file mode 100644
index 000000000..9403bd027
--- /dev/null
+++ b/internal/endtoend/testdata/geometric/pgx/v4/sqlc.json
@@ -0,0 +1,13 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "path": "go",
+      "engine": "postgresql",
+      "sql_package": "pgx/v4",
+      "name": "querytest",
+      "schema": "query.sql",
+      "queries": "query.sql"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go
index 0039bcaf4..c426a1e71 100644
--- a/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go
+++ b/internal/endtoend/testdata/join_left/sqlite/go/query.sql.go
@@ -22,8 +22,8 @@ type AllAuthorsRow struct {
 	ID         int64
 	Name       string
 	ParentID   sql.NullInt64
-	ID_2       int64
-	Name_2     string
+	ID_2       sql.NullInt64
+	Name_2     sql.NullString
 	ParentID_2 sql.NullInt64
 }
 
@@ -68,8 +68,8 @@ type AllAuthorsAliasesRow struct {
 	ID         int64
 	Name       string
 	ParentID   sql.NullInt64
-	ID_2       int64
-	Name_2     string
+	ID_2       sql.NullInt64
+	Name_2     sql.NullString
 	ParentID_2 sql.NullInt64
 }
 
@@ -114,8 +114,8 @@ type AllAuthorsAliases2Row struct {
 	ID         int64
 	Name       string
 	ParentID   sql.NullInt64
-	ID_2       int64
-	Name_2     string
+	ID_2       sql.NullInt64
+	Name_2     sql.NullString
 	ParentID_2 sql.NullInt64
 }
 
@@ -160,8 +160,8 @@ type AllSuperAuthorsRow struct {
 	ID            int64
 	Name          string
 	ParentID      sql.NullInt64
-	SuperID       int64
-	SuperName     string
+	SuperID       sql.NullInt64
+	SuperName     sql.NullString
 	SuperParentID sql.NullInt64
 }
 
@@ -206,8 +206,8 @@ type AllSuperAuthorsAliasesRow struct {
 	ID            int64
 	Name          string
 	ParentID      sql.NullInt64
-	SuperID       int64
-	SuperName     string
+	SuperID       sql.NullInt64
+	SuperName     sql.NullString
 	SuperParentID sql.NullInt64
 }
 
@@ -252,8 +252,8 @@ type AllSuperAuthorsAliases2Row struct {
 	ID            int64
 	Name          string
 	ParentID      sql.NullInt64
-	SuperID       int64
-	SuperName     string
+	SuperID       sql.NullInt64
+	SuperName     sql.NullString
 	SuperParentID sql.NullInt64
 }
 
@@ -336,8 +336,8 @@ LEFT JOIN mayors USING (mayor_id)
 
 type GetMayorsOptionalRow struct {
 	UserID   int64
-	CityID   int64
-	FullName string
+	CityID   sql.NullInt64
+	FullName sql.NullString
 }
 
 func (q *Queries) GetMayorsOptional(ctx context.Context) ([]GetMayorsOptionalRow, error) {
@@ -382,13 +382,13 @@ type GetSuggestedUsersByIDRow struct {
 	UserBio         string
 	UserCreatedAt   time.Time
 	UserAvatarID    sql.NullInt64
-	MediaID         int64
-	MediaCreatedAt  time.Time
-	MediaHash       string
-	MediaDirectory  string
-	MediaAuthorID   int64
-	MediaWidth      int64
-	MediaHeight     int64
+	MediaID         sql.NullInt64
+	MediaCreatedAt  sql.NullTime
+	MediaHash       sql.NullString
+	MediaDirectory  sql.NullString
+	MediaAuthorID   sql.NullInt64
+	MediaWidth      sql.NullInt64
+	MediaHeight     sql.NullInt64
 }
 
 func (q *Queries) GetSuggestedUsersByID(ctx context.Context, userID int64) ([]GetSuggestedUsersByIDRow, error) {
diff --git a/internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go
index dafd7cbb4..ff0fec7ba 100644
--- a/internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go
+++ b/internal/endtoend/testdata/join_left_same_table/sqlite/go/query.sql.go
@@ -7,6 +7,7 @@ package querytest
 
 import (
 	"context"
+	"database/sql"
 )
 
 const allAuthors = `-- name: AllAuthors :many
@@ -22,8 +23,8 @@ FROM    authors AS a
 type AllAuthorsRow struct {
 	ID        int64
 	Name      string
-	AliasID   int64
-	AliasName string
+	AliasID   sql.NullInt64
+	AliasName sql.NullString
 }
 
 func (q *Queries) AllAuthors(ctx context.Context) ([]AllAuthorsRow, error) {
diff --git a/internal/endtoend/testdata/join_where_clause/mysql/go/query.sql.go b/internal/endtoend/testdata/join_where_clause/mysql/go/query.sql.go
index a4b17ddf8..2b1e3f6d7 100644
--- a/internal/endtoend/testdata/join_where_clause/mysql/go/query.sql.go
+++ b/internal/endtoend/testdata/join_where_clause/mysql/go/query.sql.go
@@ -9,6 +9,41 @@ import (
 	"context"
 )
 
+const joinParamWhereClause = `-- name: JoinParamWhereClause :many
+SELECT foo.barid
+FROM foo
+JOIN bar ON bar.id = ?
+WHERE owner = ?
+`
+
+type JoinParamWhereClauseParams struct {
+	ID    uint64
+	Owner string
+}
+
+func (q *Queries) JoinParamWhereClause(ctx context.Context, arg JoinParamWhereClauseParams) ([]uint64, error) {
+	rows, err := q.db.QueryContext(ctx, joinParamWhereClause, arg.ID, arg.Owner)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []uint64
+	for rows.Next() {
+		var barid uint64
+		if err := rows.Scan(&barid); err != nil {
+			return nil, err
+		}
+		items = append(items, barid)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const joinWhereClause = `-- name: JoinWhereClause :many
 SELECT foo.barid
 FROM foo
diff --git a/internal/endtoend/testdata/join_where_clause/mysql/query.sql b/internal/endtoend/testdata/join_where_clause/mysql/query.sql
index edcf7c2a5..842e3b599 100644
--- a/internal/endtoend/testdata/join_where_clause/mysql/query.sql
+++ b/internal/endtoend/testdata/join_where_clause/mysql/query.sql
@@ -6,3 +6,9 @@ SELECT foo.*
 FROM foo
 JOIN bar ON bar.id = barid
 WHERE owner = ?;
+
+-- name: JoinParamWhereClause :many
+SELECT foo.*
+FROM foo
+JOIN bar ON bar.id = ?
+WHERE owner = ?;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/query.sql.go
index 98061a843..0dbf8d926 100644
--- a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/query.sql.go
+++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/go/query.sql.go
@@ -9,6 +9,38 @@ import (
 	"context"
 )
 
+const joinParamWhereClause = `-- name: JoinParamWhereClause :many
+SELECT foo.barid
+FROM foo
+JOIN bar ON bar.id = $2
+WHERE owner = $1
+`
+
+type JoinParamWhereClauseParams struct {
+	Owner string
+	ID    int32
+}
+
+func (q *Queries) JoinParamWhereClause(ctx context.Context, arg JoinParamWhereClauseParams) ([]int32, error) {
+	rows, err := q.db.Query(ctx, joinParamWhereClause, arg.Owner, arg.ID)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []int32
+	for rows.Next() {
+		var barid int32
+		if err := rows.Scan(&barid); err != nil {
+			return nil, err
+		}
+		items = append(items, barid)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const joinWhereClause = `-- name: JoinWhereClause :many
 SELECT foo.barid
 FROM foo
diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/query.sql
index 885042098..7705075a8 100644
--- a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/query.sql
+++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v4/query.sql
@@ -6,3 +6,9 @@ SELECT foo.*
 FROM foo
 JOIN bar ON bar.id = barid
 WHERE owner = $1;
+
+-- name: JoinParamWhereClause :many
+SELECT foo.*
+FROM foo
+JOIN bar ON bar.id = $2
+WHERE owner = $1;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/query.sql.go
index 98061a843..0dbf8d926 100644
--- a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/query.sql.go
+++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/go/query.sql.go
@@ -9,6 +9,38 @@ import (
 	"context"
 )
 
+const joinParamWhereClause = `-- name: JoinParamWhereClause :many
+SELECT foo.barid
+FROM foo
+JOIN bar ON bar.id = $2
+WHERE owner = $1
+`
+
+type JoinParamWhereClauseParams struct {
+	Owner string
+	ID    int32
+}
+
+func (q *Queries) JoinParamWhereClause(ctx context.Context, arg JoinParamWhereClauseParams) ([]int32, error) {
+	rows, err := q.db.Query(ctx, joinParamWhereClause, arg.Owner, arg.ID)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []int32
+	for rows.Next() {
+		var barid int32
+		if err := rows.Scan(&barid); err != nil {
+			return nil, err
+		}
+		items = append(items, barid)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const joinWhereClause = `-- name: JoinWhereClause :many
 SELECT foo.barid
 FROM foo
diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/query.sql
index 885042098..7705075a8 100644
--- a/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/query.sql
+++ b/internal/endtoend/testdata/join_where_clause/postgresql/pgx/v5/query.sql
@@ -6,3 +6,9 @@ SELECT foo.*
 FROM foo
 JOIN bar ON bar.id = barid
 WHERE owner = $1;
+
+-- name: JoinParamWhereClause :many
+SELECT foo.*
+FROM foo
+JOIN bar ON bar.id = $2
+WHERE owner = $1;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/query.sql.go
index 778dc0546..3fc06a5c0 100644
--- a/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/query.sql.go
+++ b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/go/query.sql.go
@@ -9,6 +9,41 @@ import (
 	"context"
 )
 
+const joinParamWhereClause = `-- name: JoinParamWhereClause :many
+SELECT foo.barid
+FROM foo
+JOIN bar ON bar.id = $2
+WHERE owner = $1
+`
+
+type JoinParamWhereClauseParams struct {
+	Owner string
+	ID    int32
+}
+
+func (q *Queries) JoinParamWhereClause(ctx context.Context, arg JoinParamWhereClauseParams) ([]int32, error) {
+	rows, err := q.db.QueryContext(ctx, joinParamWhereClause, arg.Owner, arg.ID)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []int32
+	for rows.Next() {
+		var barid int32
+		if err := rows.Scan(&barid); err != nil {
+			return nil, err
+		}
+		items = append(items, barid)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const joinWhereClause = `-- name: JoinWhereClause :many
 SELECT foo.barid
 FROM foo
diff --git a/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/query.sql b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/query.sql
index 885042098..7705075a8 100644
--- a/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/query.sql
+++ b/internal/endtoend/testdata/join_where_clause/postgresql/stdlib/query.sql
@@ -6,3 +6,9 @@ SELECT foo.*
 FROM foo
 JOIN bar ON bar.id = barid
 WHERE owner = $1;
+
+-- name: JoinParamWhereClause :many
+SELECT foo.*
+FROM foo
+JOIN bar ON bar.id = $2
+WHERE owner = $1;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go b/internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go
index a15ee4ab8..068349961 100644
--- a/internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go
+++ b/internal/endtoend/testdata/join_where_clause/sqlite/go/query.sql.go
@@ -9,6 +9,41 @@ import (
 	"context"
 )
 
+const joinParamWhereClause = `-- name: JoinParamWhereClause :many
+SELECT foo.barid
+FROM foo
+JOIN bar ON bar.id = ?
+WHERE owner = ?
+`
+
+type JoinParamWhereClauseParams struct {
+	ID    int64
+	Owner string
+}
+
+func (q *Queries) JoinParamWhereClause(ctx context.Context, arg JoinParamWhereClauseParams) ([]int64, error) {
+	rows, err := q.db.QueryContext(ctx, joinParamWhereClause, arg.ID, arg.Owner)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []int64
+	for rows.Next() {
+		var barid int64
+		if err := rows.Scan(&barid); err != nil {
+			return nil, err
+		}
+		items = append(items, barid)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const joinWhereClause = `-- name: JoinWhereClause :many
 SELECT foo.barid
 FROM foo
diff --git a/internal/endtoend/testdata/join_where_clause/sqlite/query.sql b/internal/endtoend/testdata/join_where_clause/sqlite/query.sql
index 1a9528422..10b0be603 100644
--- a/internal/endtoend/testdata/join_where_clause/sqlite/query.sql
+++ b/internal/endtoend/testdata/join_where_clause/sqlite/query.sql
@@ -6,3 +6,9 @@ SELECT foo.*
 FROM foo
 JOIN bar ON bar.id = barid
 WHERE owner = ?;
+
+-- name: JoinParamWhereClause :many
+SELECT foo.*
+FROM foo
+JOIN bar ON bar.id = ?
+WHERE owner = ?;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_test/exec.json b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/exec.json
new file mode 100644
index 000000000..7865c9ec1
--- /dev/null
+++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/exec.json
@@ -0,0 +1,3 @@
+{
+  "process": "sqlc-gen-test"
+}
\ No newline at end of file
diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_test/gen/env.json b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/gen/env.json
new file mode 100644
index 000000000..f8332e753
--- /dev/null
+++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/gen/env.json
@@ -0,0 +1,6 @@
+{
+  "env": [
+    "SQLC_VERSION=v1.20.0",
+    "SQLC_DUMMY_VALUE=true"
+  ]
+}
diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_test/query.sql b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/query.sql
new file mode 100644
index 000000000..75e38b2ca
--- /dev/null
+++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/query.sql
@@ -0,0 +1,19 @@
+-- name: GetAuthor :one
+SELECT * FROM authors
+WHERE id = $1 LIMIT 1;
+
+-- name: ListAuthors :many
+SELECT * FROM authors
+ORDER BY name;
+
+-- name: CreateAuthor :one
+INSERT INTO authors (
+          name, bio
+) VALUES (
+  $1, $2
+)
+RETURNING *;
+
+-- name: DeleteAuthor :exec
+DELETE FROM authors
+WHERE id = $1;
diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_test/schema.sql b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/schema.sql
new file mode 100644
index 000000000..b4fad7849
--- /dev/null
+++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/schema.sql
@@ -0,0 +1,5 @@
+CREATE TABLE authors (
+          id   BIGSERIAL PRIMARY KEY,
+          name text      NOT NULL,
+          bio  text
+);
diff --git a/internal/endtoend/testdata/process_plugin_sqlc_gen_test/sqlc.json b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/sqlc.json
new file mode 100644
index 000000000..a2b0e8b93
--- /dev/null
+++ b/internal/endtoend/testdata/process_plugin_sqlc_gen_test/sqlc.json
@@ -0,0 +1,25 @@
+{
+  "version": "2",
+  "sql": [
+    {
+      "schema": "schema.sql",
+      "queries": "query.sql",
+      "engine": "postgresql",
+      "codegen": [
+        {
+          "out": "gen",
+          "plugin": "test"
+        }
+      ]
+    }
+  ],
+  "plugins": [
+    {
+      "name": "test",
+      "env": ["SQLC_DUMMY_VALUE"],
+      "process": {
+        "cmd": "sqlc-gen-test"
+      }
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/db.go b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/db.go
new file mode 100644
index 000000000..57406b68e
--- /dev/null
+++ b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/db.go
@@ -0,0 +1,31 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+	"database/sql"
+)
+
+type DBTX interface {
+	ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
+	PrepareContext(context.Context, string) (*sql.Stmt, error)
+	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
+	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx *sql.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/models.go b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/models.go
new file mode 100644
index 000000000..2074349ae
--- /dev/null
+++ b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/models.go
@@ -0,0 +1,18 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"database/sql"
+	"time"
+)
+
+type Notice struct {
+	ID        int32
+	Cnt       int32
+	Status    string
+	NoticeAt  sql.NullTime
+	CreatedAt time.Time
+}
diff --git a/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/querier.go b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/querier.go
new file mode 100644
index 000000000..13f02e9f9
--- /dev/null
+++ b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/querier.go
@@ -0,0 +1,18 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+	"database/sql"
+	"time"
+)
+
+type Querier interface {
+	CreateNotice(ctx context.Context, cnt int32, createdAt time.Time) error
+	MarkNoticeDone(ctx context.Context, noticeAt sql.NullTime, iD int32) error
+}
+
+var _ Querier = (*Queries)(nil)
diff --git a/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/query.sql.go b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/query.sql.go
new file mode 100644
index 000000000..b45dbb79d
--- /dev/null
+++ b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/go/query.sql.go
@@ -0,0 +1,33 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+	"database/sql"
+	"time"
+)
+
+const createNotice = `-- name: CreateNotice :exec
+INSERT INTO notice (cnt, created_at)
+VALUES ($1, $2)
+`
+
+func (q *Queries) CreateNotice(ctx context.Context, cnt int32, createdAt time.Time) error {
+	_, err := q.db.ExecContext(ctx, createNotice, cnt, createdAt)
+	return err
+}
+
+const markNoticeDone = `-- name: MarkNoticeDone :exec
+UPDATE notice
+SET status='done', notice_at=$1
+WHERE id=$2
+`
+
+func (q *Queries) MarkNoticeDone(ctx context.Context, noticeAt sql.NullTime, iD int32) error {
+	_, err := q.db.ExecContext(ctx, markNoticeDone, noticeAt, iD)
+	return err
+}
diff --git a/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/query.sql b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/query.sql
new file mode 100644
index 000000000..7cdc56fad
--- /dev/null
+++ b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/query.sql
@@ -0,0 +1,16 @@
+CREATE TABLE notice (
+  id INTEGER NOT NULL,
+  cnt INTEGER NOT NULL,
+  status TEXT NOT NULL,
+  notice_at TIMESTAMP,
+  created_at TIMESTAMP NOT NULL
+);
+
+-- name: MarkNoticeDone :exec
+UPDATE notice
+SET status='done', notice_at=$1
+WHERE id=$2;
+
+-- name: CreateNotice :exec
+INSERT INTO notice (cnt, created_at)
+VALUES ($1, $2);
\ No newline at end of file
diff --git a/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/sqlc.json b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/sqlc.json
new file mode 100644
index 000000000..8cf64b386
--- /dev/null
+++ b/internal/endtoend/testdata/query_parameter_limit_param_only/postgresql/sqlc.json
@@ -0,0 +1,14 @@
+{
+    "version": "1",
+    "packages": [
+        {
+            "path": "go",
+            "engine": "postgresql",
+            "schema": "query.sql",
+            "queries": "query.sql",
+            "query_parameter_limit": 2,
+            "emit_interface": true,
+            "name": "querytest"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/models.go b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/models.go
index 7fbbf5fbc..683ff1177 100644
--- a/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/models.go
+++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/models.go
@@ -15,3 +15,8 @@ type Author struct {
 	CountryCode string
 	Titles      []string
 }
+
+type Client struct {
+	ID   int32
+	Name string
+}
diff --git a/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/query.sql.go b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/query.sql.go
index 867290c04..19a289d2f 100644
--- a/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/query.sql.go
+++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/go/query.sql.go
@@ -13,6 +13,22 @@ import (
 	"github.com/lib/pq"
 )
 
+const addNewClient = `-- name: AddNewClient :one
+INSERT INTO clients (
+  id, name
+) VALUES (
+  $1, $2
+)
+RETURNING id, name
+`
+
+func (q *Queries) AddNewClient(ctx context.Context, iD int32, name string) (Client, error) {
+	row := q.db.QueryRowContext(ctx, addNewClient, iD, name)
+	var i Client
+	err := row.Scan(&i.ID, &i.Name)
+	return i, err
+}
+
 const createAuthor = `-- name: CreateAuthor :one
 INSERT INTO authors (
   name, bio, country_code, titles
diff --git a/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/query.sql b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/query.sql
index 8edd6ae9b..13ee235bd 100644
--- a/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/query.sql
+++ b/internal/endtoend/testdata/query_parameter_limit_to_two/postgresql/query.sql
@@ -33,3 +33,16 @@ WHERE id IN (sqlc.slice(ids)) AND name = $1;
 
 -- name: CreateAuthorOnlyTitles :one
 INSERT INTO authors (name, titles) VALUES ($1, $2) RETURNING *;
+
+CREATE TABLE clients (
+  id INT PRIMARY KEY,
+  name TEXT NOT NULL
+);
+
+-- name: AddNewClient :one
+INSERT INTO clients (
+  id, name
+) VALUES (
+  $1, $2
+)
+RETURNING *;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/schema_scoped_list/mysql/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_list/mysql/go/query.sql.go
index 7b26fd358..236fff199 100644
--- a/internal/endtoend/testdata/schema_scoped_list/mysql/go/query.sql.go
+++ b/internal/endtoend/testdata/schema_scoped_list/mysql/go/query.sql.go
@@ -9,6 +9,33 @@ import (
 	"context"
 )
 
+const schemaScopedColList = `-- name: SchemaScopedColList :many
+SELECT foo.bar.id FROM foo.bar
+`
+
+func (q *Queries) SchemaScopedColList(ctx context.Context) ([]uint64, error) {
+	rows, err := q.db.QueryContext(ctx, schemaScopedColList)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []uint64
+	for rows.Next() {
+		var id uint64
+		if err := rows.Scan(&id); err != nil {
+			return nil, err
+		}
+		items = append(items, id)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const schemaScopedList = `-- name: SchemaScopedList :many
 SELECT id FROM foo.bar
 `
diff --git a/internal/endtoend/testdata/schema_scoped_list/mysql/query.sql b/internal/endtoend/testdata/schema_scoped_list/mysql/query.sql
index cb8d6cdb6..43b898c02 100644
--- a/internal/endtoend/testdata/schema_scoped_list/mysql/query.sql
+++ b/internal/endtoend/testdata/schema_scoped_list/mysql/query.sql
@@ -3,3 +3,6 @@ CREATE TABLE foo.bar (id serial not null);
 
 -- name: SchemaScopedList :many
 SELECT * FROM foo.bar;
+
+-- name: SchemaScopedColList :many
+SELECT foo.bar.id FROM foo.bar;
diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/query.sql.go
index 1e0f26b3e..655ab97f6 100644
--- a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/query.sql.go
+++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/go/query.sql.go
@@ -9,6 +9,30 @@ import (
 	"context"
 )
 
+const schemaScopedColList = `-- name: SchemaScopedColList :many
+SELECT foo.bar.id FROM foo.bar
+`
+
+func (q *Queries) SchemaScopedColList(ctx context.Context) ([]int32, error) {
+	rows, err := q.db.Query(ctx, schemaScopedColList)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []int32
+	for rows.Next() {
+		var id int32
+		if err := rows.Scan(&id); err != nil {
+			return nil, err
+		}
+		items = append(items, id)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const schemaScopedList = `-- name: SchemaScopedList :many
 SELECT id FROM foo.bar
 `
diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/query.sql
index cb8d6cdb6..ef7b01859 100644
--- a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/query.sql
+++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v4/query.sql
@@ -3,3 +3,6 @@ CREATE TABLE foo.bar (id serial not null);
 
 -- name: SchemaScopedList :many
 SELECT * FROM foo.bar;
+
+-- name: SchemaScopedColList :many
+SELECT foo.bar.id FROM foo.bar;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/query.sql.go
index 1e0f26b3e..655ab97f6 100644
--- a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/query.sql.go
+++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/go/query.sql.go
@@ -9,6 +9,30 @@ import (
 	"context"
 )
 
+const schemaScopedColList = `-- name: SchemaScopedColList :many
+SELECT foo.bar.id FROM foo.bar
+`
+
+func (q *Queries) SchemaScopedColList(ctx context.Context) ([]int32, error) {
+	rows, err := q.db.Query(ctx, schemaScopedColList)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []int32
+	for rows.Next() {
+		var id int32
+		if err := rows.Scan(&id); err != nil {
+			return nil, err
+		}
+		items = append(items, id)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const schemaScopedList = `-- name: SchemaScopedList :many
 SELECT id FROM foo.bar
 `
diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/query.sql
index cb8d6cdb6..ef7b01859 100644
--- a/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/query.sql
+++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/pgx/v5/query.sql
@@ -3,3 +3,6 @@ CREATE TABLE foo.bar (id serial not null);
 
 -- name: SchemaScopedList :many
 SELECT * FROM foo.bar;
+
+-- name: SchemaScopedColList :many
+SELECT foo.bar.id FROM foo.bar;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/query.sql.go
index 07a890b45..d31382c9a 100644
--- a/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/query.sql.go
+++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/go/query.sql.go
@@ -9,6 +9,33 @@ import (
 	"context"
 )
 
+const schemaScopedColList = `-- name: SchemaScopedColList :many
+SELECT foo.bar.id FROM foo.bar
+`
+
+func (q *Queries) SchemaScopedColList(ctx context.Context) ([]int32, error) {
+	rows, err := q.db.QueryContext(ctx, schemaScopedColList)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []int32
+	for rows.Next() {
+		var id int32
+		if err := rows.Scan(&id); err != nil {
+			return nil, err
+		}
+		items = append(items, id)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
 const schemaScopedList = `-- name: SchemaScopedList :many
 SELECT id FROM foo.bar
 `
diff --git a/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/query.sql b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/query.sql
index cb8d6cdb6..ef7b01859 100644
--- a/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/query.sql
+++ b/internal/endtoend/testdata/schema_scoped_list/postgresql/stdlib/query.sql
@@ -3,3 +3,6 @@ CREATE TABLE foo.bar (id serial not null);
 
 -- name: SchemaScopedList :many
 SELECT * FROM foo.bar;
+
+-- name: SchemaScopedColList :many
+SELECT foo.bar.id FROM foo.bar;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/select_union/mysql/go/models.go b/internal/endtoend/testdata/select_union/mysql/go/models.go
index c0cab4c64..635378fe8 100644
--- a/internal/endtoend/testdata/select_union/mysql/go/models.go
+++ b/internal/endtoend/testdata/select_union/mysql/go/models.go
@@ -8,6 +8,11 @@ import (
 	"database/sql"
 )
 
+type Bar struct {
+	A sql.NullString
+	B sql.NullString
+}
+
 type Foo struct {
 	A sql.NullString
 	B sql.NullString
diff --git a/internal/endtoend/testdata/select_union/mysql/go/query.sql.go b/internal/endtoend/testdata/select_union/mysql/go/query.sql.go
index 96147809a..3c937f9b8 100644
--- a/internal/endtoend/testdata/select_union/mysql/go/query.sql.go
+++ b/internal/endtoend/testdata/select_union/mysql/go/query.sql.go
@@ -95,3 +95,67 @@ func (q *Queries) SelectUnion(ctx context.Context) ([]Foo, error) {
 	}
 	return items, nil
 }
+
+const selectUnionOther = `-- name: SelectUnionOther :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM bar
+`
+
+func (q *Queries) SelectUnionOther(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectUnionOther)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const selectUnionWithLimit = `-- name: SelectUnionWithLimit :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM foo
+LIMIT ? OFFSET ?
+`
+
+type SelectUnionWithLimitParams struct {
+	Limit  int32
+	Offset int32
+}
+
+func (q *Queries) SelectUnionWithLimit(ctx context.Context, arg SelectUnionWithLimitParams) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectUnionWithLimit, arg.Limit, arg.Offset)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/select_union/mysql/query.sql b/internal/endtoend/testdata/select_union/mysql/query.sql
index 80dd8cc4f..f8aca8b15 100644
--- a/internal/endtoend/testdata/select_union/mysql/query.sql
+++ b/internal/endtoend/testdata/select_union/mysql/query.sql
@@ -1,10 +1,17 @@
 CREATE TABLE foo (a text, b text);
+CREATE TABLE bar (a text, b text);
 
 -- name: SelectUnion :many
 SELECT * FROM foo
 UNION
 SELECT * FROM foo;
 
+-- name: SelectUnionWithLimit :many
+SELECT * FROM foo
+UNION
+SELECT * FROM foo
+LIMIT ? OFFSET ?;
+
 -- name: SelectExcept :many
 SELECT * FROM foo
 EXCEPT
@@ -14,3 +21,8 @@ SELECT * FROM foo;
 SELECT * FROM foo
 INTERSECT
 SELECT * FROM foo;
+
+-- name: SelectUnionOther :many
+SELECT * FROM foo
+UNION
+SELECT * FROM bar;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/models.go b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/models.go
index c0cab4c64..635378fe8 100644
--- a/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/models.go
+++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/models.go
@@ -8,6 +8,11 @@ import (
 	"database/sql"
 )
 
+type Bar struct {
+	A sql.NullString
+	B sql.NullString
+}
+
 type Foo struct {
 	A sql.NullString
 	B sql.NullString
diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/query.sql.go
index d2cfd2e0d..5977586a2 100644
--- a/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/query.sql.go
+++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/go/query.sql.go
@@ -86,3 +86,61 @@ func (q *Queries) SelectUnion(ctx context.Context) ([]Foo, error) {
 	}
 	return items, nil
 }
+
+const selectUnionOther = `-- name: SelectUnionOther :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM bar
+`
+
+func (q *Queries) SelectUnionOther(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.Query(ctx, selectUnionOther)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const selectUnionWithLimit = `-- name: SelectUnionWithLimit :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM foo
+LIMIT $1 OFFSET $2
+`
+
+type SelectUnionWithLimitParams struct {
+	Limit  int32
+	Offset int32
+}
+
+func (q *Queries) SelectUnionWithLimit(ctx context.Context, arg SelectUnionWithLimitParams) ([]Foo, error) {
+	rows, err := q.db.Query(ctx, selectUnionWithLimit, arg.Limit, arg.Offset)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v4/query.sql b/internal/endtoend/testdata/select_union/postgres/pgx/v4/query.sql
index 80dd8cc4f..a2fafc7d0 100644
--- a/internal/endtoend/testdata/select_union/postgres/pgx/v4/query.sql
+++ b/internal/endtoend/testdata/select_union/postgres/pgx/v4/query.sql
@@ -1,10 +1,17 @@
 CREATE TABLE foo (a text, b text);
+CREATE TABLE bar (a text, b text);
 
 -- name: SelectUnion :many
 SELECT * FROM foo
 UNION
 SELECT * FROM foo;
 
+-- name: SelectUnionWithLimit :many
+SELECT * FROM foo
+UNION
+SELECT * FROM foo
+LIMIT $1 OFFSET $2;
+
 -- name: SelectExcept :many
 SELECT * FROM foo
 EXCEPT
@@ -14,3 +21,8 @@ SELECT * FROM foo;
 SELECT * FROM foo
 INTERSECT
 SELECT * FROM foo;
+
+-- name: SelectUnionOther :many
+SELECT * FROM foo
+UNION
+SELECT * FROM bar;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/models.go b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/models.go
index db5fe749f..269271c12 100644
--- a/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/models.go
+++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/models.go
@@ -8,6 +8,11 @@ import (
 	"github.com/jackc/pgx/v5/pgtype"
 )
 
+type Bar struct {
+	A pgtype.Text
+	B pgtype.Text
+}
+
 type Foo struct {
 	A pgtype.Text
 	B pgtype.Text
diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/query.sql.go
index d2cfd2e0d..5977586a2 100644
--- a/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/query.sql.go
+++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/go/query.sql.go
@@ -86,3 +86,61 @@ func (q *Queries) SelectUnion(ctx context.Context) ([]Foo, error) {
 	}
 	return items, nil
 }
+
+const selectUnionOther = `-- name: SelectUnionOther :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM bar
+`
+
+func (q *Queries) SelectUnionOther(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.Query(ctx, selectUnionOther)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const selectUnionWithLimit = `-- name: SelectUnionWithLimit :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM foo
+LIMIT $1 OFFSET $2
+`
+
+type SelectUnionWithLimitParams struct {
+	Limit  int32
+	Offset int32
+}
+
+func (q *Queries) SelectUnionWithLimit(ctx context.Context, arg SelectUnionWithLimitParams) ([]Foo, error) {
+	rows, err := q.db.Query(ctx, selectUnionWithLimit, arg.Limit, arg.Offset)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/select_union/postgres/pgx/v5/query.sql b/internal/endtoend/testdata/select_union/postgres/pgx/v5/query.sql
index 80dd8cc4f..a2fafc7d0 100644
--- a/internal/endtoend/testdata/select_union/postgres/pgx/v5/query.sql
+++ b/internal/endtoend/testdata/select_union/postgres/pgx/v5/query.sql
@@ -1,10 +1,17 @@
 CREATE TABLE foo (a text, b text);
+CREATE TABLE bar (a text, b text);
 
 -- name: SelectUnion :many
 SELECT * FROM foo
 UNION
 SELECT * FROM foo;
 
+-- name: SelectUnionWithLimit :many
+SELECT * FROM foo
+UNION
+SELECT * FROM foo
+LIMIT $1 OFFSET $2;
+
 -- name: SelectExcept :many
 SELECT * FROM foo
 EXCEPT
@@ -14,3 +21,8 @@ SELECT * FROM foo;
 SELECT * FROM foo
 INTERSECT
 SELECT * FROM foo;
+
+-- name: SelectUnionOther :many
+SELECT * FROM foo
+UNION
+SELECT * FROM bar;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/select_union/postgres/stdlib/go/models.go b/internal/endtoend/testdata/select_union/postgres/stdlib/go/models.go
index c0cab4c64..635378fe8 100644
--- a/internal/endtoend/testdata/select_union/postgres/stdlib/go/models.go
+++ b/internal/endtoend/testdata/select_union/postgres/stdlib/go/models.go
@@ -8,6 +8,11 @@ import (
 	"database/sql"
 )
 
+type Bar struct {
+	A sql.NullString
+	B sql.NullString
+}
+
 type Foo struct {
 	A sql.NullString
 	B sql.NullString
diff --git a/internal/endtoend/testdata/select_union/postgres/stdlib/go/query.sql.go b/internal/endtoend/testdata/select_union/postgres/stdlib/go/query.sql.go
index 96147809a..0b638e949 100644
--- a/internal/endtoend/testdata/select_union/postgres/stdlib/go/query.sql.go
+++ b/internal/endtoend/testdata/select_union/postgres/stdlib/go/query.sql.go
@@ -95,3 +95,67 @@ func (q *Queries) SelectUnion(ctx context.Context) ([]Foo, error) {
 	}
 	return items, nil
 }
+
+const selectUnionOther = `-- name: SelectUnionOther :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM bar
+`
+
+func (q *Queries) SelectUnionOther(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectUnionOther)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const selectUnionWithLimit = `-- name: SelectUnionWithLimit :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM foo
+LIMIT $1 OFFSET $2
+`
+
+type SelectUnionWithLimitParams struct {
+	Limit  int32
+	Offset int32
+}
+
+func (q *Queries) SelectUnionWithLimit(ctx context.Context, arg SelectUnionWithLimitParams) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectUnionWithLimit, arg.Limit, arg.Offset)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/select_union/postgres/stdlib/query.sql b/internal/endtoend/testdata/select_union/postgres/stdlib/query.sql
index 80dd8cc4f..a2fafc7d0 100644
--- a/internal/endtoend/testdata/select_union/postgres/stdlib/query.sql
+++ b/internal/endtoend/testdata/select_union/postgres/stdlib/query.sql
@@ -1,10 +1,17 @@
 CREATE TABLE foo (a text, b text);
+CREATE TABLE bar (a text, b text);
 
 -- name: SelectUnion :many
 SELECT * FROM foo
 UNION
 SELECT * FROM foo;
 
+-- name: SelectUnionWithLimit :many
+SELECT * FROM foo
+UNION
+SELECT * FROM foo
+LIMIT $1 OFFSET $2;
+
 -- name: SelectExcept :many
 SELECT * FROM foo
 EXCEPT
@@ -14,3 +21,8 @@ SELECT * FROM foo;
 SELECT * FROM foo
 INTERSECT
 SELECT * FROM foo;
+
+-- name: SelectUnionOther :many
+SELECT * FROM foo
+UNION
+SELECT * FROM bar;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/select_union/sqlite/go/db.go b/internal/endtoend/testdata/select_union/sqlite/go/db.go
new file mode 100644
index 000000000..57406b68e
--- /dev/null
+++ b/internal/endtoend/testdata/select_union/sqlite/go/db.go
@@ -0,0 +1,31 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+	"database/sql"
+)
+
+type DBTX interface {
+	ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
+	PrepareContext(context.Context, string) (*sql.Stmt, error)
+	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
+	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx *sql.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/select_union/sqlite/go/models.go b/internal/endtoend/testdata/select_union/sqlite/go/models.go
new file mode 100644
index 000000000..635378fe8
--- /dev/null
+++ b/internal/endtoend/testdata/select_union/sqlite/go/models.go
@@ -0,0 +1,19 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"database/sql"
+)
+
+type Bar struct {
+	A sql.NullString
+	B sql.NullString
+}
+
+type Foo struct {
+	A sql.NullString
+	B sql.NullString
+}
diff --git a/internal/endtoend/testdata/select_union/sqlite/go/query.sql.go b/internal/endtoend/testdata/select_union/sqlite/go/query.sql.go
new file mode 100644
index 000000000..a38fd5db9
--- /dev/null
+++ b/internal/endtoend/testdata/select_union/sqlite/go/query.sql.go
@@ -0,0 +1,161 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const selectExcept = `-- name: SelectExcept :many
+SELECT a, b FROM foo
+EXCEPT
+SELECT a, b FROM foo
+`
+
+func (q *Queries) SelectExcept(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectExcept)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const selectIntersect = `-- name: SelectIntersect :many
+SELECT a, b FROM foo
+INTERSECT
+SELECT a, b FROM foo
+`
+
+func (q *Queries) SelectIntersect(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectIntersect)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const selectUnion = `-- name: SelectUnion :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM foo
+`
+
+func (q *Queries) SelectUnion(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectUnion)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const selectUnionOther = `-- name: SelectUnionOther :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM bar
+`
+
+func (q *Queries) SelectUnionOther(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectUnionOther)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const selectUnionWithLimit = `-- name: SelectUnionWithLimit :many
+SELECT a, b FROM foo
+UNION
+SELECT a, b FROM foo
+LIMIT ? OFFSET ?
+`
+
+type SelectUnionWithLimitParams struct {
+	Limit  int64
+	Offset int64
+}
+
+func (q *Queries) SelectUnionWithLimit(ctx context.Context, arg SelectUnionWithLimitParams) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, selectUnionWithLimit, arg.Limit, arg.Offset)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/select_union/sqlite/query.sql b/internal/endtoend/testdata/select_union/sqlite/query.sql
new file mode 100644
index 000000000..f8aca8b15
--- /dev/null
+++ b/internal/endtoend/testdata/select_union/sqlite/query.sql
@@ -0,0 +1,28 @@
+CREATE TABLE foo (a text, b text);
+CREATE TABLE bar (a text, b text);
+
+-- name: SelectUnion :many
+SELECT * FROM foo
+UNION
+SELECT * FROM foo;
+
+-- name: SelectUnionWithLimit :many
+SELECT * FROM foo
+UNION
+SELECT * FROM foo
+LIMIT ? OFFSET ?;
+
+-- name: SelectExcept :many
+SELECT * FROM foo
+EXCEPT
+SELECT * FROM foo;
+
+-- name: SelectIntersect :many
+SELECT * FROM foo
+INTERSECT
+SELECT * FROM foo;
+
+-- name: SelectUnionOther :many
+SELECT * FROM foo
+UNION
+SELECT * FROM bar;
\ No newline at end of file
diff --git a/internal/endtoend/testdata/select_union/sqlite/sqlc.json b/internal/endtoend/testdata/select_union/sqlite/sqlc.json
new file mode 100644
index 000000000..fc58be5b0
--- /dev/null
+++ b/internal/endtoend/testdata/select_union/sqlite/sqlc.json
@@ -0,0 +1,12 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "engine": "sqlite",
+      "path": "go",
+      "name": "querytest",
+      "schema": "query.sql",
+      "queries": "query.sql"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/star_expansion/mysql/go/query.sql.go b/internal/endtoend/testdata/star_expansion/mysql/go/query.sql.go
index 8f8d72b09..6738b4ff6 100644
--- a/internal/endtoend/testdata/star_expansion/mysql/go/query.sql.go
+++ b/internal/endtoend/testdata/star_expansion/mysql/go/query.sql.go
@@ -52,3 +52,30 @@ func (q *Queries) StarExpansion(ctx context.Context) ([]StarExpansionRow, error)
 	}
 	return items, nil
 }
+
+const starQuotedExpansion = `-- name: StarQuotedExpansion :many
+SELECT t.a, t.b FROM foo ` + "`" + `t` + "`" + `
+`
+
+func (q *Queries) StarQuotedExpansion(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, starQuotedExpansion)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/star_expansion/mysql/query.sql b/internal/endtoend/testdata/star_expansion/mysql/query.sql
index d330c646f..4515ce46e 100644
--- a/internal/endtoend/testdata/star_expansion/mysql/query.sql
+++ b/internal/endtoend/testdata/star_expansion/mysql/query.sql
@@ -2,3 +2,6 @@ CREATE TABLE foo (a text, b text);
 
 /* name: StarExpansion :many */
 SELECT *, *, foo.* FROM foo;
+
+/* name: StarQuotedExpansion :many */
+SELECT `t`.* FROM foo `t`;
diff --git a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/query.sql.go
index 904e5d615..1fc5ae5f5 100644
--- a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/query.sql.go
+++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/go/query.sql.go
@@ -49,3 +49,27 @@ func (q *Queries) StarExpansion(ctx context.Context) ([]StarExpansionRow, error)
 	}
 	return items, nil
 }
+
+const starQuotedExpansion = `-- name: StarQuotedExpansion :many
+SELECT t.a, t.b FROM foo "t"
+`
+
+func (q *Queries) StarQuotedExpansion(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.Query(ctx, starQuotedExpansion)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/query.sql
index 0305062fb..77ef29f8e 100644
--- a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/query.sql
+++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v4/query.sql
@@ -2,3 +2,6 @@ CREATE TABLE foo (a text, b text);
 
 -- name: StarExpansion :many
 SELECT *, *, foo.* FROM foo;
+
+-- name: StarQuotedExpansion :many
+SELECT "t".* FROM foo "t";
\ No newline at end of file
diff --git a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/query.sql.go
index 56a635f89..206b188a0 100644
--- a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/query.sql.go
+++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/go/query.sql.go
@@ -50,3 +50,27 @@ func (q *Queries) StarExpansion(ctx context.Context) ([]StarExpansionRow, error)
 	}
 	return items, nil
 }
+
+const starQuotedExpansion = `-- name: StarQuotedExpansion :many
+SELECT t.a, t.b FROM foo "t"
+`
+
+func (q *Queries) StarQuotedExpansion(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.Query(ctx, starQuotedExpansion)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/query.sql
index 0305062fb..77ef29f8e 100644
--- a/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/query.sql
+++ b/internal/endtoend/testdata/star_expansion/postgresql/pgx/v5/query.sql
@@ -2,3 +2,6 @@ CREATE TABLE foo (a text, b text);
 
 -- name: StarExpansion :many
 SELECT *, *, foo.* FROM foo;
+
+-- name: StarQuotedExpansion :many
+SELECT "t".* FROM foo "t";
\ No newline at end of file
diff --git a/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/query.sql.go
index 8f8d72b09..b7e6b55a6 100644
--- a/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/query.sql.go
+++ b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/go/query.sql.go
@@ -52,3 +52,30 @@ func (q *Queries) StarExpansion(ctx context.Context) ([]StarExpansionRow, error)
 	}
 	return items, nil
 }
+
+const starQuotedExpansion = `-- name: StarQuotedExpansion :many
+SELECT t.a, t.b FROM foo "t"
+`
+
+func (q *Queries) StarQuotedExpansion(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, starQuotedExpansion)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/star_expansion/postgresql/stdlib/query.sql b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/query.sql
index 0305062fb..77ef29f8e 100644
--- a/internal/endtoend/testdata/star_expansion/postgresql/stdlib/query.sql
+++ b/internal/endtoend/testdata/star_expansion/postgresql/stdlib/query.sql
@@ -2,3 +2,6 @@ CREATE TABLE foo (a text, b text);
 
 -- name: StarExpansion :many
 SELECT *, *, foo.* FROM foo;
+
+-- name: StarQuotedExpansion :many
+SELECT "t".* FROM foo "t";
\ No newline at end of file
diff --git a/internal/endtoend/testdata/star_expansion/sqlite/go/db.go b/internal/endtoend/testdata/star_expansion/sqlite/go/db.go
new file mode 100644
index 000000000..57406b68e
--- /dev/null
+++ b/internal/endtoend/testdata/star_expansion/sqlite/go/db.go
@@ -0,0 +1,31 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"context"
+	"database/sql"
+)
+
+type DBTX interface {
+	ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
+	PrepareContext(context.Context, string) (*sql.Stmt, error)
+	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
+	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx *sql.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/star_expansion/sqlite/go/models.go b/internal/endtoend/testdata/star_expansion/sqlite/go/models.go
new file mode 100644
index 000000000..c0cab4c64
--- /dev/null
+++ b/internal/endtoend/testdata/star_expansion/sqlite/go/models.go
@@ -0,0 +1,14 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+
+package querytest
+
+import (
+	"database/sql"
+)
+
+type Foo struct {
+	A sql.NullString
+	B sql.NullString
+}
diff --git a/internal/endtoend/testdata/star_expansion/sqlite/go/query.sql.go b/internal/endtoend/testdata/star_expansion/sqlite/go/query.sql.go
new file mode 100644
index 000000000..b7e6b55a6
--- /dev/null
+++ b/internal/endtoend/testdata/star_expansion/sqlite/go/query.sql.go
@@ -0,0 +1,81 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.20.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+	"database/sql"
+)
+
+const starExpansion = `-- name: StarExpansion :many
+SELECT a, b, a, b, foo.a, foo.b FROM foo
+`
+
+type StarExpansionRow struct {
+	A   sql.NullString
+	B   sql.NullString
+	A_2 sql.NullString
+	B_2 sql.NullString
+	A_3 sql.NullString
+	B_3 sql.NullString
+}
+
+func (q *Queries) StarExpansion(ctx context.Context) ([]StarExpansionRow, error) {
+	rows, err := q.db.QueryContext(ctx, starExpansion)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []StarExpansionRow
+	for rows.Next() {
+		var i StarExpansionRow
+		if err := rows.Scan(
+			&i.A,
+			&i.B,
+			&i.A_2,
+			&i.B_2,
+			&i.A_3,
+			&i.B_3,
+		); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const starQuotedExpansion = `-- name: StarQuotedExpansion :many
+SELECT t.a, t.b FROM foo "t"
+`
+
+func (q *Queries) StarQuotedExpansion(ctx context.Context) ([]Foo, error) {
+	rows, err := q.db.QueryContext(ctx, starQuotedExpansion)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Foo
+	for rows.Next() {
+		var i Foo
+		if err := rows.Scan(&i.A, &i.B); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
diff --git a/internal/endtoend/testdata/star_expansion/sqlite/query.sql b/internal/endtoend/testdata/star_expansion/sqlite/query.sql
new file mode 100644
index 000000000..6cc850628
--- /dev/null
+++ b/internal/endtoend/testdata/star_expansion/sqlite/query.sql
@@ -0,0 +1,7 @@
+CREATE TABLE foo (a text, b text);
+
+-- name: StarExpansion :many
+SELECT *, *, foo.* FROM foo;
+
+-- name: StarQuotedExpansion :many
+SELECT "t".* FROM foo "t";
diff --git a/internal/endtoend/testdata/star_expansion/sqlite/sqlc.json b/internal/endtoend/testdata/star_expansion/sqlite/sqlc.json
new file mode 100644
index 000000000..fc58be5b0
--- /dev/null
+++ b/internal/endtoend/testdata/star_expansion/sqlite/sqlc.json
@@ -0,0 +1,12 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "engine": "sqlite",
+      "path": "go",
+      "name": "querytest",
+      "schema": "query.sql",
+      "queries": "query.sql"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/gen/env.json b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/gen/env.json
new file mode 100644
index 000000000..f8332e753
--- /dev/null
+++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/gen/env.json
@@ -0,0 +1,6 @@
+{
+  "env": [
+    "SQLC_VERSION=v1.20.0",
+    "SQLC_DUMMY_VALUE=true"
+  ]
+}
diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/query.sql b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/query.sql
new file mode 100644
index 000000000..75e38b2ca
--- /dev/null
+++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/query.sql
@@ -0,0 +1,19 @@
+-- name: GetAuthor :one
+SELECT * FROM authors
+WHERE id = $1 LIMIT 1;
+
+-- name: ListAuthors :many
+SELECT * FROM authors
+ORDER BY name;
+
+-- name: CreateAuthor :one
+INSERT INTO authors (
+          name, bio
+) VALUES (
+  $1, $2
+)
+RETURNING *;
+
+-- name: DeleteAuthor :exec
+DELETE FROM authors
+WHERE id = $1;
diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/schema.sql b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/schema.sql
new file mode 100644
index 000000000..b4fad7849
--- /dev/null
+++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/schema.sql
@@ -0,0 +1,5 @@
+CREATE TABLE authors (
+          id   BIGSERIAL PRIMARY KEY,
+          name text      NOT NULL,
+          bio  text
+);
diff --git a/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/sqlc.json b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/sqlc.json
new file mode 100644
index 000000000..38e6773a2
--- /dev/null
+++ b/internal/endtoend/testdata/wasm_plugin_sqlc_gen_test/sqlc.json
@@ -0,0 +1,26 @@
+{
+  "version": "2",
+  "sql": [
+    {
+      "schema": "schema.sql",
+      "queries": "query.sql",
+      "engine": "postgresql",
+      "codegen": [
+        {
+          "out": "gen",
+          "plugin": "test"
+        }
+      ]
+    }
+  ],
+  "plugins": [
+    {
+      "name": "test",
+      "env": ["SQLC_DUMMY_VALUE"],
+      "wasm": {
+        "url": "https://github.com/sqlc-dev/sqlc-gen-test/releases/download/v0.1.0/sqlc-gen-test.wasm",
+        "sha256": "138220eae508d4b65a5a8cea555edd155eb2290daf576b7a8b96949acfeb3790"
+      }
+    }
+  ]
+}
\ No newline at end of file